feat: Implement automated OpenAPI type generation
Add automated type synchronization from backend OpenAPI schema to frontend TypeScript types to prevent type drift and ensure runtime safety. Changes: - Add openapi-typescript as dev dependency - Create npm scripts for type generation (generate:types) and validation (validate:types) - Integrate type generation into build pipeline (runs before TypeScript compilation) - Generate frontend/src/types/generated.ts from backend OpenAPI schema - Add frontend/scripts/validate-types.sh for CI/CD validation - Update Web-Development.md with type generation workflow documentation - Update Backend-Development.md with OpenAPI schema sync requirements Workflow: 1. Backend automatically exposes OpenAPI schema at /api/openapi.json (FastAPI built-in) 2. Frontend build runs 'npm run generate:types' to generate types from schema 3. Generated types are committed to version control 4. CI can run 'npm run validate:types' to fail builds if types drift Fixes critical type safety issue where frontend types were manually maintained and could become out of sync with backend Pydantic models. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -293,10 +293,31 @@ async def get_jails(state: JailServiceStateDep) -> JailListResponse:
|
||||
# Good — pass db=None on GET so geo_service never commits
|
||||
result = await geo_service.lookup_batch(ips, http_session, db=None)
|
||||
|
||||
# Bad — triggers INSERT + COMMIT per IP inside a GET handler
|
||||
# Bad — triggers INSERT + COMMIT per GET inside a GET handler
|
||||
result = await geo_service.lookup_batch(ips, http_session, db=app_db)
|
||||
```
|
||||
|
||||
### OpenAPI Schema Synchronization
|
||||
|
||||
**Critical:** The OpenAPI schema is the single source of truth for frontend types. When you add, modify, or remove endpoints or response models:
|
||||
|
||||
1. **FastAPI automatically updates the schema** based on your Pydantic models and endpoint definitions.
|
||||
2. **The frontend regenerates types** from the schema on every build: `npm run generate:types`.
|
||||
3. **Ensure your Pydantic models are accurate** — they are directly serialized into the schema and used to generate frontend types.
|
||||
4. **Test type generation locally** before committing:
|
||||
```bash
|
||||
cd frontend
|
||||
npm run generate:types # Generates src/types/generated.ts
|
||||
npm run build # Build should succeed if types match
|
||||
```
|
||||
5. **The backend must be running** for type generation to work (the tool fetches `/api/openapi.json`).
|
||||
6. **Commit generated types** alongside backend changes — they must always be in sync.
|
||||
|
||||
**Never:**
|
||||
- Manually edit `src/types/generated.ts` on the frontend — regenerate from the schema instead.
|
||||
- Commit backend changes without ensuring the frontend can regenerate types.
|
||||
- Assume the OpenAPI schema is correct — validate your Pydantic model's `field` descriptions and types are as intended.
|
||||
|
||||
```python
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from app.models.jail import JailResponse, JailListResponse
|
||||
@@ -310,6 +331,7 @@ async def list_jails(service: JailService = Depends()) -> JailListResponse:
|
||||
return JailListResponse(jails=jails)
|
||||
```
|
||||
|
||||
|
||||
### Dependency Layering: Enforcing the Repository Boundary
|
||||
|
||||
The **repository boundary** separates database-aware code from application logic. This is enforced through dependency injection.
|
||||
|
||||
@@ -69,6 +69,50 @@ import type { Ban } from "../types/ban";
|
||||
|
||||
---
|
||||
|
||||
## 2.5. Generated Types from OpenAPI Schema
|
||||
|
||||
**Critical:** Frontend types are automatically generated from the backend's OpenAPI schema to prevent type drift. This ensures frontend types always match the backend's Pydantic models.
|
||||
|
||||
### Workflow
|
||||
|
||||
1. **Backend exposes OpenAPI schema** at `GET /api/openapi.json` (enabled automatically by FastAPI).
|
||||
2. **Frontend builds include type generation:**
|
||||
```bash
|
||||
npm run generate:types # Generates src/types/generated.ts
|
||||
npm run build # Automatically calls generate:types first
|
||||
```
|
||||
3. **Generated types** (`src/types/generated.ts`) are committed to version control and imported wherever needed.
|
||||
4. **CI validation** ensures generated types stay in sync with the backend:
|
||||
```bash
|
||||
npm run validate:types # Fails if types differ from backend schema
|
||||
```
|
||||
|
||||
### When Backend Models Change
|
||||
|
||||
1. Modify the Pydantic model in `backend/app/models/` as needed.
|
||||
2. Ensure the change is reflected in the OpenAPI schema (FastAPI does this automatically).
|
||||
3. On the next build, `npm run generate:types` regenerates types from the new schema.
|
||||
4. The build fails if types differ (pre-commit hook can catch this locally).
|
||||
5. Commit the updated `src/types/generated.ts` alongside your backend changes.
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Add `npm run validate:types` to your CI pipeline to catch type drift:
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Validate types
|
||||
run: npm run validate:types
|
||||
```
|
||||
|
||||
The script returns:
|
||||
- **Exit 0:** Types are in sync
|
||||
- **Exit 1:** Generated types differ (run `npm run generate:types` to fix)
|
||||
- **Exit 2:** Backend is not accessible (set `BANGUI_BACKEND_URL` if needed)
|
||||
- **Exit 3:** Type generation failed
|
||||
|
||||
---
|
||||
|
||||
## 3. Type Safety in API Calls
|
||||
|
||||
- Every API call must have a **typed request** and **typed response**.
|
||||
|
||||
Reference in New Issue
Block a user