Assignment 1 – Build your first API

Build your own API

In this assignment you will be tasked to build your own server that will serve as an API. You will be building a fully functional server that could, if deployed to the cloud, serve real live internet traffic and be integrated as a part of a web application.

Summary

You will be building a server that can keep track of tasks. Your server must be able to do the following:

  1. Create a new task with a title property and a boolean determining whether the task has been completed. A new unique id would be created for each new task
  2. List all tasks created
  3. Get a specific task
  4. Delete a specified task
  5. Edit the title or completion of a specific task
  6. Bulk add multiple tasks in one request
  7. Bulk delete multiple tasks in one request

Your application will accept JSON and/or URL parameters and will return JSON data. Your server would be ready to be automatically integrated in a web system.

NOTE: Please make the id’s of the task sequential. As in when you create a first task, assign it id = 1, and the next one number id =2. Even if you delete a task, please still assign the next created task the next sequential number.

List of endpoints to be created

Here is a specific list of endpoints that you will be required to create, along with the method and the inputs/outputs:

Create a new Task

POST /v1/tasks

Input

{title: "Test Task 2"}

Output

{id: 2} (return a 201 code)

The id returned is a unique id for the todo that was just created

List all tasks created

GET /v1/tasks

Input

None

Output

(return a 200 code)
{
   tasks: [
     {id: 1, title: "Test Task 1", is_completed: true},
     {id: 2, title: "Test Task 2", is_completed: false}
   ]
}

Notes

This endpoint list all tasks including their id's

Get a specific task

GET /v1/tasks/{id}

Input

id (passed through the URL)

Output

(return a 200 code)
{id: 3, title: "Test Task 2", is_completed: false}

On Error

if id not found:
(return a 404 code)

{ 
    error: "There is no task at that id"
}

Notes

This endpoint returns a specific task or returns a 404 not found response

Delete a specific task

DELETE /v1/tasks/{id}

Input

id (passed through the URL)

Output

None (return a 204 code)

Notes: This endpoint deletes a specific task. If the task doesn’t exist still send the same response

Edit the title or completion of a specific task

PUT /v1/tasks/{id}

Input

{title: "Test Task 2", is_completed: false}

Output

None (return a 204 code)

On Error

if id not found:
(return a 404 code)

{ 
    error: "There is no task at that id"
}

Notes: This endpoint deletes a specific task or returns a 404 not found response

Bulk add tasks

POST /v1/tasks

Input

{
   tasks: [
      {title: "Test Task 1", is_completed: true},
      {title: "Test Task 2", is_completed: false},
      {title: "Test Task 3", is_completed: true}
   ]
}

Output

(return a 201 code)
{
   tasks: [
      {id: 1},
      {id: 2},
      {id: 3}
   ]
}

Notes: This endpoint bulk adds more than one task. Note that this feature uses the same endpoint as the single task creation endpoint

Bulk delete tasks

DELETE /v1/tasks

Input

{
   tasks: [
     {id: 1},
     {id: 2},
     {id: 3}
  ]
}

Output

None (return a 204 code)

Notes: This endpoint bulk deletes more than one task.

Tests

To see if you are on the right track, run the below file (using pytest, while your server is running) to test your endpoints. This is not an extensive test.

This test is to ensure that you have all of the routes correct and that your response is properly formed. For example, ensuring that your GET /v1/tasks/{id} endpoint returns a dictionary with an id (a number), a title (a string), and whether the task is completed (boolean).

Note: please run this as the first thing that hits your server on boot up. If it successfully completes once then your assignment is on the right track. Re-running the tests could fail as written.

So in short:

  • Start your webserver
  • Run your tests once
  • If pass you are good!
import requests
import json

def test_create_task():
    r = requests.post('http://localhost:5000/v1/tasks', json={"title": "My First Task"})
    assert isinstance(r.json()["id"], int)
    assert len(r.json()) == 1

def test_list_all_tasks():
    r = requests.get('http://localhost:5000/v1/tasks')
    assert isinstance(r.json()["tasks"], list)
    assert len(r.json()) == 1
    assert isinstance(r.json()["tasks"][0]["id"], int)
    assert isinstance(r.json()["tasks"][0]["title"], str)
    assert isinstance(r.json()["tasks"][0]["is_completed"], bool)
    assert len(r.json()["tasks"][0]) == 3

def test_get_task():
    r = requests.get('http://localhost:5000/v1/tasks/1')
    assert isinstance(r.json(),dict)
    assert isinstance(r.json()["id"], int)
    assert isinstance(r.json()["title"], str)
    assert isinstance(r.json()["is_completed"], bool)
    assert len(r.json()) == 3

def test_update_task():
    r = requests.put('http://localhost:5000/v1/tasks/1', json={"title": "My 1st Task", "is_completed": True})
    assert not r.content

def test_delete_task():
    r = requests.delete('http://localhost:5000/v1/tasks/1')
    assert not r.content

Submission

Be sure to push all of your code in the repository you created earlier.

Please submit the URL of your repository to BCourses. This is important so that we know whose repository is whose in the class.