minimal_api.py

script

← Back to skill

Content hash: 63f6518f77b39ace2573c4e44020a41ec5bc0e494e703b350f0b393d21b61ccc
#!/usr/bin/env python3
"""Minimal FastAPI application with routing, validation, dependency injection, and tests.

Run:    uvicorn minimal_api:app --reload
Test:   pytest minimal_api.py -v
"""

from __future__ import annotations

from fastapi import APIRouter, Depends, FastAPI, HTTPException
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

# ── App ─────────────────────────────────────────────────────────────────

app = FastAPI(title="Skills API", version="1.0.0")

# ── Schemas ─────────────────────────────────────────────────────────────

class SkillCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=64)
    description: str = Field(..., min_length=10)

class SkillResponse(BaseModel):
    id: str
    name: str
    description: str

# ── Dependencies ────────────────────────────────────────────────────────

# Simulated database; in production, use a real DB connection via Depends.
_db: dict[str, dict] = {}

def get_db() -> dict:
    return _db

# ── Router ──────────────────────────────────────────────────────────────

router = APIRouter(prefix="/skills", tags=["skills"])

@router.post("/", status_code=201, response_model=SkillResponse)
def create_skill(payload: SkillCreate, db: dict = Depends(get_db)) -> SkillResponse:
    sid = f"skill-{len(db) + 1}"
    db[sid] = {"id": sid, "name": payload.name, "description": payload.description}
    return SkillResponse(**db[sid])

@router.get("/{skill_id}", response_model=SkillResponse)
def get_skill(skill_id: str, db: dict = Depends(get_db)) -> SkillResponse:
    if skill_id not in db:
        raise HTTPException(status_code=404, detail="Skill not found")
    return SkillResponse(**db[skill_id])

app.include_router(router)

# ── Health check ────────────────────────────────────────────────────────

@app.get("/health")
def health() -> dict:
    return {"status": "ok"}

# ── Tests ───────────────────────────────────────────────────────────────

client = TestClient(app)

def test_create_and_get():
    r = client.post("/skills/", json={"name": "pytest", "description": "Testing framework"})
    assert r.status_code == 201
    sid = r.json()["id"]

    r2 = client.get(f"/skills/{sid}")
    assert r2.status_code == 200
    assert r2.json()["name"] == "pytest"

def test_validation():
    r = client.post("/skills/", json={"name": "", "description": "short"})
    assert r.status_code == 422

def test_not_found():
    r = client.get("/skills/nonexistent")
    assert r.status_code == 404