Skip to main content
Web MobileIntermediate16 min readUpdated March 2025

Building REST APIs with FastAPI

Build a validated, documented REST API in Python with FastAPI, then call it from JavaScript. Covers models, CRUD routes, status codes and CORS.

REST Principles

A REST API exposes resources as URLs and uses HTTP methods to act on them:

  • GET `/tasks` — list tasks
  • POST `/tasks` — create a task
  • GET `/tasks/{id}` — read one task
  • PUT `/tasks/{id}` — update a task
  • DELETE `/tasks/{id}` — remove a task

A Complete FastAPI Service

FastAPI uses Python type hints and Pydantic models to validate input automatically and generate interactive docs at `/docs`. Run with `uvicorn main:app --reload`.

python
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field

app = FastAPI(title="Tasks API")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_methods=["*"],
    allow_headers=["*"],
)

class TaskIn(BaseModel):
    title: str = Field(min_length=1, max_length=120)
    done: bool = False

class Task(TaskIn):
    id: int

db: dict[int, Task] = {}
next_id = 1

@app.get("/tasks", response_model=list[Task])
def list_tasks():
    return list(db.values())

@app.post("/tasks", response_model=Task, status_code=201)
def create_task(payload: TaskIn):
    global next_id
    task = Task(id=next_id, **payload.model_dump())
    db[next_id] = task
    next_id += 1
    return task

@app.get("/tasks/{task_id}", response_model=Task)
def get_task(task_id: int):
    if task_id not in db:
        raise HTTPException(status_code=404, detail="Task not found")
    return db[task_id]

@app.delete("/tasks/{task_id}", status_code=204)
def delete_task(task_id: int):
    if db.pop(task_id, None) is None:
        raise HTTPException(status_code=404, detail="Task not found")

Calling the API from JavaScript

A small client wrapper keeps error handling in one place:

javascript
const API = "http://localhost:8000";

async function request(path, options = {}) {
  const res = await fetch(`${API}${path}`, {
    headers: { "Content-Type": "application/json" },
    ...options,
  });
  if (!res.ok) {
    const detail = await res.json().catch(() => ({}));
    throw new Error(detail.detail || `HTTP ${res.status}`);
  }
  return res.status === 204 ? null : res.json();
}

export const createTask = (title) =>
  request("/tasks", { method: "POST", body: JSON.stringify({ title }) });

export const listTasks = () => request("/tasks");

const task = await createTask("Write docs");
console.log(task, await listTasks());

Status Codes to Know

Return meaningful codes so clients can react correctly:

  • 200 OK, 201 Created, 204 No Content
  • 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Validation Error
  • 500 Internal Server Error

Key Takeaways

  • REST maps resources to URLs and actions to HTTP methods.
  • FastAPI validates input with type hints and generates docs automatically.
  • Configure CORS explicitly for browser clients.
  • Return accurate status codes and consistent error bodies.

Contact Us

Have a question or feedback? Fill out the form below or reach us directly at support@nvaitraining.com