Step 2 - TODO API endpoints =========================== In this section of **TODO** how to we are going to create the following API endpoints: +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | **Endpoint** | **HTTP verb** | **HTTP Body** | **Description** | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | /tasks | GET | None | Retrieves available tasks in a paginated manner. | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | /tasks | POST | {"name": "Task name", "description": "Task description"} | Creates a new task described by the given body. | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | /tasks/:task_id | GET | | Retrieves a specific task from tasks collection. | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | /tasks/:task_id | PUT | {"name": "Task name changed", "description": "Task description changed"} | Updates a specific task from tasks collection. | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ | /tasks/:task_id | DELETE | None | Deletes a specific task from tasks collection. | +-----------------+---------------+--------------------------------------------------------------------------+--------------------------------------------------+ These are going to provide support for various clients which want to provide TODO functionality: * Javascript frontend client. * Mobile app client. Create database --------------- Our TODO tasks are going to be persisted by the endpoints into a MySql database (already created in previous steps). Now, we are going to create tasks tables: #. git checkout -b step-2-create-api #. Paste the code below under fantastico-todo/todo/frontend/sql/module_setup.sql .. code-block:: sql CREATE TABLE IF NOT EXISTS tasks( task_id INT NOT NULL AUTO_INCREMENT, name VARCHAR(200) NOT NULL, description TEXT, status SMALLINT, PRIMARY KEY(task_id) ); #. Execute the following command in order to create the table into **tododb** database: .. code-block:: bash fsdk syncdb --db-command /usr/bin/mysql --comp-root todo #. Create some sample uncompleted tasks in your database: #. Paste the code below in fantastico-todo/todo/frontend/sql/create_data.sql: .. code-block:: sql INSERT INTO tasks(name, description, status) SELECT * FROM (SELECT 'Go buy some dog food.', 'It is extremely important to have this by noon.', 0) as tmp WHERE NOT EXISTS(SELECT name FROM tasks WHERE name = 'Go buy some dog food.'); INSERT INTO tasks(name, description, status) SELECT * FROM (SELECT 'Write some clean code.', 'You decide when to start this.', 0) as tmp WHERE NOT EXISTS(SELECT name FROM tasks WHERE name = 'Write some clean code.'); #. Execute the following command in order to insert above mentioned tasks into **tododb** database: .. code-block:: bash fsdk syncdb --db-command /usr/bin/mysql --comp-root todo Create APIs ----------- Now that the storage is ensured and our project is configured correctly we have to create the APIs. In order to do this follow the steps below: #. fsdk activate-extension --name roa_discovery --comp-root todo #. Paste the code below in fantastico-todo/todo/frontend/models/tasks.py .. code-block:: python from fantastico.mvc import BASEMODEL from fantastico.roa.resource_decorator import Resource from sqlalchemy.schema import Column from sqlalchemy.types import Integer, String, Text, SmallInteger from todo.frontend.validators.task_validator import TaskValidator @Resource(name="Task", url="/tasks", validator=TaskValidator) class Task(BASEMODEL): '''This class provides the task model required for todo application.''' __tablename__ = "tasks" task_id = Column("task_id", Integer, primary_key=True, autoincrement=True) name = Column("name", String(200), nullable=False) description = Column("description", Text) status = Column("status", SmallInteger, nullable=False) def __init__(self, name=None, description=None, status=0): self.name = name self.description = description self.status = status #. Paste the code below in fantastico-todo/todo/frontend/validators/task_validator.py .. code-block:: python from fantastico.roa.resource_validator import ResourceValidator from fantastico.roa.roa_exceptions import FantasticoRoaError class TaskValidator(ResourceValidator): '''This is the task validator invoked automatically in create / update operations.''' def validate(self, resource): '''This method is invoked automatically in order to validate resource body.''' errors = [] if resource.name is None or len(resource.name) == 0: errors.append("Name attribute is mandatory.") if resource.status is None: errors.append("Status attribute is mandatory.") if len(errors) == 0: return raise FantasticoRoaError("\n".join(errors)) #. Run the following command in an activate fantastico-todo virtual environment: .. code-block:: bash fantastico_run_dev_server #. Visit ``_. You should see a response similar to the one below: .. image:: /images/how_to/todo/roa_discovered_resources.png #. Visit ``_. You should see a response similar to the one below: .. image:: /images/how_to/todo/roa_tasks_initial_listing.png #. Visit ``_. You should receive the details for the task with unique identifier 1. #. Additionally Create / Update / Delete operations are already working.