Skip to content

API Endpoint Generator — Med Tracker

Generate a complete CRUD API endpoint following the established Med Tracker patterns.

Usage

/api-endpoint <resource_name>

Example: /api-endpoint allergies

What Gets Created

For a resource named {name}:

FilePurpose
backend/app/schemas/{name}.pyPydantic v2 Create/Update/Response schemas
backend/app/api/v1/{name}.pyFastAPI router with CRUD endpoints
backend/tests/test_{name}_endpoints.pypytest-asyncio test suite
Update backend/app/main.pyRegister new router

Schema Pattern (app/schemas/{name}.py)

python
from pydantic import BaseModel, Field
from datetime import datetime

class {Name}Create(BaseModel):
    # Required fields with validation
    field: str = Field(..., min_length=1, max_length=200)

class {Name}Update(BaseModel):
    # All fields optional for partial update
    field: str | None = None

class {Name}Response(BaseModel):
    id: str
    user_id: str
    created_at: datetime
    updated_at: datetime
    # ... resource fields

Route Pattern (app/api/v1/{name}.py)

python
from fastapi import APIRouter, Depends, HTTPException
from app.api.deps import get_current_user, get_supabase_client
from app.schemas.{name} import {Name}Create, {Name}Update, {Name}Response

router = APIRouter(prefix="/api/v1/{name}s", tags=["{name}s"])

@router.get("/")
async def list_{name}s(user=Depends(get_current_user), db=Depends(get_supabase_client)):
    result = db.table("{name}s").select("*").eq("user_id", user.id).execute()
    return {"{name}s": result.data}

@router.post("/", status_code=201)
async def create_{name}(payload: {Name}Create, user=Depends(get_current_user), db=Depends(get_supabase_client)):
    data = {**payload.model_dump(), "user_id": user.id}
    result = db.table("{name}s").insert(data).execute()
    return result.data[0]

@router.patch("/{id}")
async def update_{name}(id: str, payload: {Name}Update, user=Depends(get_current_user), db=Depends(get_supabase_client)):
    updates = {k: v for k, v in payload.model_dump(exclude_unset=True).items()}
    result = db.table("{name}s").update(updates).eq("id", id).eq("user_id", user.id).execute()
    if not result.data:
        raise HTTPException(status_code=404, detail="{Name} not found")
    return result.data[0]

@router.delete("/{id}", status_code=204)
async def delete_{name}(id: str, user=Depends(get_current_user), db=Depends(get_supabase_client)):
    result = db.table("{name}s").delete().eq("id", id).eq("user_id", user.id).execute()
    if not result.data:
        raise HTTPException(status_code=404, detail="{Name} not found")

Test Pattern (tests/test_{name}_endpoints.py)

Follow TDD — write tests FIRST, then implement:

python
import pytest
from unittest.mock import MagicMock

@pytest.fixture
def mock_user():
    user = MagicMock()
    user.id = "test-user-id"
    return user

class TestList{Name}s:
    async def test_returns_user_scoped_data(self, client, mock_supabase, mock_user):
        mock_supabase.table().select().eq().execute.return_value.data = []
        response = await client.get("/api/v1/{name}s")
        assert response.status_code == 200

class TestCreate{Name}:
    async def test_creates_with_valid_data(self, client, mock_supabase, mock_user):
        mock_supabase.table().insert().execute.return_value.data = [{"id": "new-id"}]
        response = await client.post("/api/v1/{name}s", json={...})
        assert response.status_code == 201

Registration (app/main.py)

Add to the router imports and registrations:

python
from app.api.v1.{name} import router as {name}_router
app.include_router({name}_router)

Checklist

  • [ ] Schema with proper Pydantic v2 validation (Field constraints)
  • [ ] All 4 CRUD operations (list, create, update, delete)
  • [ ] User scoping via eq("user_id", user.id) on ALL queries
  • [ ] 404 handling on update/delete
  • [ ] Tests written FIRST (TDD RED phase)
  • [ ] Router registered in main.py
  • [ ] datetime.now(UTC) for timestamps (not utcnow())
  • [ ] ruff check passes (ruff check app/)
  • [ ] Full test suite passes (pytest)

Read-only documentation bundle of the Med Tracker agent stack. AU compliance baked in (AHPRA + Privacy Act 1988 + Spam Act 2003).