Loading...
Loading...
API development workflow and best practices for career_ios_backend FastAPI project. Automatically invoked when user wants to develop, test, or debug API endpoints. Trigger keywords: "API", "endpoint", "route", "FastAPI", "Swagger", "console.html", "測試 API", "API 開發", "端點" Covers development flow, testing requirements, and console integration.
npx skill4agent add youngger9765/career_ios_backend api-development1. Write Feature Code (AI-Assisted)
↓ 70% time
2. Manual Test API (Swagger UI or Console)
↓ Quick verification
3. Write Integration Test (Verify API works)
↓ 20% time
4. ruff check --fix (Auto-fix formatting)
↓ Auto
5. Commit (Pre-commit hooks)
↓ ~5s
6. Push → CI runs Integration Tests
↓ ~2 minconsole.html# Daily development: Run integration tests only
poetry run pytest tests/integration/ -v
# Full test suite (optional during development)
poetry run pytest tests/ -v
# Test specific API
poetry run pytest tests/integration/test_auth_api.py -vtest_auth_api.pytest_clients_api.pytest_sessions_api.pytest_cases_api.pytest_reports_api.pytest_rag_*.pyauth_headers# Verify test coverage
poetry run pytest tests/integration/ -v | grep -E "(test_.*_api\.py|PASSED|FAILED)"
# Current coverage (106+ tests):
✅ Authentication (login, token refresh)
✅ Client Management (CRUD, search, code generation)
✅ Session Management (CRUD, transcripts, reflections)
✅ Case Management (CRUD, timeline)
✅ Report Generation (consultation reports)
✅ RAG Features (upload, embed, search, evaluate)1. Design API behavior
↓
2. Write integration test FIRST
↓ (test in tests/integration/)
3. Run test → RED (fails)
↓
4. Implement API endpoint
↓
5. Run test → GREEN (passes)
↓
6. Update console.html to use API
↓
7. Manual test in browser consoleapp/
├── api/
│ ├── auth.py # Authentication endpoints
│ ├── clients.py # Client management
│ ├── sessions.py # Session/consultation
│ ├── cases.py # Case management
│ └── <feature>.py # New feature routes
├── models/
│ ├── user.py # SQLAlchemy models
│ ├── client.py
│ └── <feature>.py # New feature models
├── schemas/
│ ├── client.py # Pydantic schemas (request/response)
│ └── <feature>.py
├── services/ # Business logic (optional)
│ └── <feature>_service.py
└── main.py # App initialization, router registration# app/api/my_feature.py
from fastapi import APIRouter, Depends
router = APIRouter(prefix="/api/v1/my-feature", tags=["my-feature"])
@router.get("/")
async def list_items():
return {"items": []}# app/schemas/my_feature.py
from pydantic import BaseModel
class ItemCreate(BaseModel):
name: str
description: str
class ItemResponse(BaseModel):
id: int
name: strmain.pyfrom app.api import my_feature
app.include_router(my_feature.router)# tests/integration/test_my_feature_api.py
@pytest.mark.asyncio
async def test_list_items(auth_headers):
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.get(
"/api/v1/my-feature/",
headers=auth_headers
)
assert response.status_code == 200# Start development server
poetry run uvicorn app.main:app --reload
# Open Swagger UI
http://localhost:8000/docs
# Features:
- Interactive API testing
- Auto-generated from FastAPI
- Try out endpoints directly
- See request/response schemas# 1. Start backend
poetry run uvicorn app.main:app --reload
# 2. Open console.html in browser
open console.html
# 3. Test workflows:
- Login
- Create client
- Add session
- Generate report
- etc.# Quick test script (for complex scenarios)
import httpx
import asyncio
async def test_api():
async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
# Login
response = await client.post("/api/v1/auth/login", json={
"username": "testuser",
"password": "testpass"
})
token = response.json()["access_token"]
# Test endpoint
response = await client.get(
"/api/v1/clients/",
headers={"Authorization": f"Bearer {token}"}
)
print(response.json())
asyncio.run(test_api())from app.core.security import get_current_user
@router.get("/protected")
async def protected_route(current_user = Depends(get_current_user)):
return {"user": current_user.username}auth_headers@pytest.mark.asyncio
async def test_protected_endpoint(auth_headers):
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.get(
"/api/v1/protected",
headers=auth_headers # Provides valid JWT token
)
assert response.status_code == 200# Test unauthenticated access (should fail)
@pytest.mark.asyncio
async def test_endpoint_requires_auth():
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.get("/api/v1/protected")
assert response.status_code == 401 # Unauthorizedtests/conftest.pyfrom app.db.session import get_db
from sqlalchemy.orm import Session
@router.post("/clients")
async def create_client(
client_data: ClientCreate,
db: Session = Depends(get_db)
):
# Use db session for database operations
new_client = Client(**client_data.dict())
db.add(new_client)
db.commit()
db.refresh(new_client)
return new_client# Run all integration tests
poetry run pytest tests/integration/ -v
# Run specific test file
poetry run pytest tests/integration/test_clients_api.py -v
# Run specific test
poetry run pytest tests/integration/test_clients_api.py::test_create_client -v
# Run tests with coverage report (optional)
poetry run pytest tests/integration/ --cov=app --cov-report=html
# Run tests matching pattern
poetry run pytest -k "client" -v# CREATE
@router.post("/", response_model=ItemResponse, status_code=201)
async def create_item(item: ItemCreate, db: Session = Depends(get_db)):
...
# READ (list)
@router.get("/", response_model=List[ItemResponse])
async def list_items(db: Session = Depends(get_db)):
...
# READ (single)
@router.get("/{item_id}", response_model=ItemResponse)
async def get_item(item_id: int, db: Session = Depends(get_db)):
...
# UPDATE
@router.put("/{item_id}", response_model=ItemResponse)
async def update_item(item_id: int, item: ItemUpdate, db: Session = Depends(get_db)):
...
# DELETE
@router.delete("/{item_id}", status_code=204)
async def delete_item(item_id: int, db: Session = Depends(get_db)):
...from fastapi import HTTPException
@router.get("/{item_id}")
async def get_item(item_id: int, db: Session = Depends(get_db)):
item = db.query(Item).filter(Item.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return itemtdd-workflow skill activates:
↓
1. RED: Write integration test (fails)
→ tests/integration/test_<feature>_api.py
↓
2. GREEN: Implement API endpoint (passes)
→ app/api/<feature>.py
↓
3. REFACTOR: Code review and quality check
↓
4. git-workflow skill: Commit and pushtdd-workflow# Check conftest.py has database fixtures
# Ensure test uses proper fixtures
@pytest.mark.asyncio
async def test_endpoint(db_session): # Use db fixture
...# Ensure PYTHONPATH includes project root
# Run from project root directory
cd /path/to/career_ios_backend
poetry run pytest tests/integration/ -v# Verify router is registered in main.py
# Check route prefix and path
# Start server and check Swagger UI: /docs