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:

  1. git checkout -b step-2-create-api

  2. Paste the code below under fantastico-todo/todo/frontend/sql/module_setup.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)
    );
    
  3. Execute the following command in order to create the table into tododb database:

    fsdk syncdb --db-command /usr/bin/mysql --comp-root todo
    
  4. Create some sample uncompleted tasks in your database:

    1. Paste the code below in fantastico-todo/todo/frontend/sql/create_data.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.');
      
    2. Execute the following command in order to insert above mentioned tasks into tododb database:

      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:

  1. fsdk activate-extension –name roa_discovery –comp-root todo

  2. Paste the code below in fantastico-todo/todo/frontend/models/tasks.py

    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
    
  3. Paste the code below in fantastico-todo/todo/frontend/validators/task_validator.py

    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))
    
  4. Run the following command in an activate fantastico-todo virtual environment:

    fantastico_run_dev_server
    
  5. Visit http://localhost:12000/roa/resources. You should see a response similar to the one below:

    ../../_images/roa_discovered_resources.png
  6. Visit http://localhost:12000/api/latest/tasks. You should see a response similar to the one below:

    ../../_images/roa_tasks_initial_listing.png
  7. Visit http://localhost:12000/api/latest/tasks/1. You should receive the details for the task with unique identifier 1.

  8. Additionally Create / Update / Delete operations are already working.