This is the first part of a two-part series on creating a serverless API using Fast API
Fast API
FastAPI is a modern, high-performance web framework for building APIs with Python based on standard type hints. It has the following key features:
- Fast - Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic)
- Fast to Code - Increases developer productivity to ship code faster
- Fewer Bugs - Reduces human-induced errors
- Intuitive - Great editor support
- East - Designed to be easy to learn and code
- Short - Minimize code duplication
- Robust - It provides production-ready code with automatic interactive documentation.
- Standards-based - It’s based on the open standards for APIs, Open API, and JSON Schema.
Let's create a small to-do app that uses an in-memory data store.
Structuring the codebase
Let's structure the app like below

- The app folder contains everything related to the app
- The model contains all the models
- The router contains a route for each use case
- The service contains the business logic
The Model
For the model we use below code -
from pydantic import BaseModel
from typing import Union
class Todo(BaseModel):
id: Union[str, None] = None
todo: str
The Router
The router has the below routes -
from fastapi import APIRouter, HTTPException
import app.service.todo as todo_service
from app.model.todo import Todo
router = APIRouter(
prefix="/todos",
tags=["todos"],
responses={404: {"description": "Not found"}},
)
@router.get("/")
async def read_todos():
return await todo_service.read_todos()
@router.post("/")
async def create_todo(todo: Todo):
return await todo_service.create_todo(todo)
@router.get("/{todo_id}")
async def read_todo(todo_id: str):
todo = await todo_service.read_todo(todo_id)
if todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return todo
@router.delete("/{todo_id}")
async def delete_todo(todo_id: str):
todo = await todo_service.read_todo(todo_id)
if todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return await todo_service.delete_todo(todo_id)
We use the @router annotation for various HTTP verbs
The router calls the service which has the business logic
The Service
Service details -
import uuid
from typing import List
from app.model.todo import Todo
todos_db: List[Todo] = []
async def read_todos():
return todos_db
async def create_todo(todo: Todo):
todo.id = str(uuid.uuid4())
todos_db.append(todo)
return todo
async def read_todo(todo_id: str):
for todo in todos_db:
if todo.id == todo_id:
return todo
return None
async def delete_todo(todo_id: str):
t = None
for todo in todos_db:
if todo.id == todo_id:
t = todo
if t is not None:
todos_db.remove(t)
else:
return None
Service handles the generic CRUD operation with an in-memory data store called todos_db.
Putting it all together
The main app needs to be configured this way -
from fastapi import FastAPI
from .router import todo
app = FastAPI(
title="Todos API",
description="Todos API with in memory Database",
)
app.include_router(todo.router)
@app.get("/", tags=["health"])
async def root():
return {"status": "Success", "message": "App is running!"}
The title and description will be used for the out-of-box Open API specification.
Final Step
Fast API can be run with uvicorn server. Let's run it with the below configuration
import uvicorn
host="0.0.0.0"
port=8002
app_name="app.main:app"
if __name__ == '__main__':
uvicorn.run(app_name, host=host, port=port)
Okay, now let's run the code.
python .\main.py
We get amazing open API specs out of the box 😍
Go to http//:localhost:8002/docs and we get the open API specs

We can now run the API using the docs or any REST API client
Hope you like it! Do give it a try.
Oh! Here's the GitHub repository to play with the code