DEV Community

Art Baker
Art Baker

Posted on

The FastAPI Starter Template I Wish I Had When I Started

Every FastAPI project starts the same way: copy-paste from the docs, manually set up CORS, figure out Pydantic models, write a Dockerfile, remember how TestClient works.

I got tired of doing this every time, so I made a clean starter template. Here's what's in it and why.

The structure

fastapi_starter/
├── main.py           # CRUD API with models, CORS, error handling
├── test_main.py      # pytest suite with TestClient
├── Dockerfile        # Production container
├── requirements.txt  # Pinned deps
└── README.md         # Quick start guide
Enter fullscreen mode Exit fullscreen mode

main.py — the whole API in 50 lines

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

app = FastAPI(title="API", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])

class Item(BaseModel):
    name: str
    description: str = ""
    price: float

items: dict[int, Item] = {}
next_id = 1

@app.post("/items", status_code=201)
def create_item(item: Item):
    global next_id
    items[next_id] = item
    next_id += 1
    return {"id": next_id - 1, **item.dict()}

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in items:
        raise HTTPException(404, "Item not found")
    return {"id": item_id, **items[item_id].dict()}
Enter fullscreen mode Exit fullscreen mode

CORS is on by default (you'll forget otherwise). Pydantic handles validation. HTTPException gives clean error responses.

test_main.py — 5 tests that actually matter

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_create_and_get():
    r = client.post("/items", json={"name": "Widget", "price": 9.99})
    assert r.status_code == 201
    r2 = client.get(f"/items/{r.json()['id']}")
    assert r2.json()["name"] == "Widget"

def test_not_found():
    assert client.get("/items/999").status_code == 404
Enter fullscreen mode Exit fullscreen mode

Run with pytest test_main.py -v. No external DB needed — the in-memory store makes tests fast and isolated.

Dockerfile — one command to deploy

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

docker build -t myapi . && docker run -p 8000:8000 myapi — done.

What I'd add next

  1. SQLAlchemy + Alembic for a real database
  2. OAuth2 + JWT authentication
  3. Rate limiting middleware
  4. Background tasks with Celery or ARQ

But the template is deliberately minimal — it gives you a clean starting point without opinions you'll have to undo.


Full starter template (main.py + tests + Docker + README): payhip.com/b/2ptFz ($7)

Also available:

Top comments (0)