Assignment 1: Build your own API

Build your own API – Due Monday, March 9th

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. (Extra Credit) Bulk add multiple tasks in one request
  7. (Extra Credit) 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.

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

(Extra Credit) 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

(Extra Credit) 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

Please use the repository you created in week2. You will need to add all of your code to that repository and use the git commands to stage, commit, and push your code to GitHub. Please check that lab’s instructions to make sure you are set up and ready to go.

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