Files
syndarix/frontend/docs/MSW_AUTO_GENERATION.md
Felipe Cardoso 29074f26a6 Remove outdated documentation files
- Deleted `I18N_IMPLEMENTATION_PLAN.md` and `PROJECT_PROGRESS.md` to declutter the repository.
- These documents were finalized, no longer relevant, and superseded by implemented features and external references.
2025-11-27 18:55:29 +01:00

405 lines
9.7 KiB
Markdown

# MSW Auto-Generation from OpenAPI
## Overview
MSW (Mock Service Worker) handlers are **automatically generated** from your OpenAPI specification, ensuring perfect synchronization between your backend API and demo mode.
## Architecture
```
Backend API Changes
npm run generate:api
┌─────────────────────────────────────┐
│ 1. Fetches OpenAPI spec │
│ 2. Generates TypeScript API client │
│ 3. Generates MSW handlers │
└─────────────────────────────────────┘
src/mocks/handlers/
├── generated.ts (AUTO-GENERATED - DO NOT EDIT)
├── overrides.ts (CUSTOM LOGIC - EDIT AS NEEDED)
└── index.ts (MERGES BOTH)
```
## How It Works
### 1. Automatic Generation
When you run:
```bash
npm run generate:api
```
The system:
1. Fetches `/api/v1/openapi.json` from backend
2. Generates TypeScript API client (`src/lib/api/generated/`)
3. **NEW:** Generates MSW handlers (`src/mocks/handlers/generated.ts`)
### 2. Generated Handlers
The generator (`scripts/generate-msw-handlers.ts`) creates handlers with:
**Smart Response Logic:**
- **Auth endpoints** → Use `validateCredentials()` and `setCurrentUser()`
- **User endpoints** → Use `currentUser` and mock data
- **Admin endpoints** → Check `is_superuser` + return paginated data
- **Generic endpoints** → Return success response
**Example Generated Handler:**
```typescript
/**
* Login
*/
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request, params }) => {
await delay(NETWORK_DELAY);
const body = (await request.json()) as any;
const user = validateCredentials(body.email, body.password);
if (!user) {
return HttpResponse.json(
{ detail: 'Incorrect email or password' },
{ status: 401 }
);
}
const accessToken = `demo-access-${user.id}-${Date.now()}`;
const refreshToken = `demo-refresh-${user.id}-${Date.now()}`;
setCurrentUser(user);
return HttpResponse.json({
access_token: accessToken,
refresh_token: refreshToken,
token_type: 'bearer',
expires_in: 900,
});
}),
```
### 3. Custom Overrides
For complex logic that can't be auto-generated, use `overrides.ts`:
```typescript
// src/mocks/handlers/overrides.ts
export const overrideHandlers = [
// Example: Simulate rate limiting
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request }) => {
// 10% chance of rate limit
if (Math.random() < 0.1) {
return HttpResponse.json({ detail: 'Too many login attempts' }, { status: 429 });
}
// Fall through to generated handler
}),
// Example: Complex validation
http.post(`${API_BASE_URL}/api/v1/users`, async ({ request }) => {
const body = await request.json();
// Custom validation logic
if (body.email.endsWith('@blocked.com')) {
return HttpResponse.json({ detail: 'Email domain not allowed' }, { status: 400 });
}
// Fall through to generated handler
}),
];
```
**Override Precedence:**
Overrides are applied FIRST, so they take precedence over generated handlers.
## Benefits
### ✅ Zero Manual Work
**Before:**
```bash
# Backend adds new endpoint
# 1. Run npm run generate:api
# 2. Manually add MSW handler
# 3. Test demo mode
# 4. Fix bugs
# 5. Repeat for every endpoint change
```
**After:**
```bash
# Backend adds new endpoint
npm run generate:api # Done! MSW auto-synced
```
### ✅ Always In Sync
- OpenAPI spec is single source of truth
- Generator reads same spec as API client
- Impossible to have mismatched endpoints
- New endpoints automatically available in demo mode
### ✅ Type-Safe
```typescript
// Generated handlers use your mock data
import { validateCredentials, currentUser } from '../data/users';
import { sampleOrganizations } from '../data/organizations';
import { adminStats } from '../data/stats';
// Everything is typed!
```
### ✅ Batteries Included
Generated handlers include:
- ✅ Network delays (300ms - realistic UX)
- ✅ Auth checks (401/403 responses)
- ✅ Pagination support
- ✅ Path parameters
- ✅ Request body parsing
- ✅ Proper HTTP methods
## File Structure
```
frontend/
├── scripts/
│ ├── generate-api-client.sh # Main generation script
│ └── generate-msw-handlers.ts # MSW handler generator
├── src/
│ ├── lib/api/generated/ # Auto-generated API client
│ │ ├── client.gen.ts
│ │ ├── sdk.gen.ts
│ │ └── types.gen.ts
│ │
│ └── mocks/
│ ├── browser.ts # MSW setup
│ ├── data/ # Mock data (EDIT THESE)
│ │ ├── users.ts
│ │ ├── organizations.ts
│ │ └── stats.ts
│ └── handlers/
│ ├── generated.ts # ⚠️ AUTO-GENERATED
│ ├── overrides.ts # ✅ EDIT FOR CUSTOM LOGIC
│ └── index.ts # Merges both
```
## Workflow
### Adding New Backend Endpoint
1. **Add endpoint to backend** (FastAPI route)
2. **Regenerate clients:**
```bash
cd frontend
npm run generate:api
```
3. **Test demo mode:**
```bash
NEXT_PUBLIC_DEMO_MODE=true npm run dev
```
4. **Done!** New endpoint automatically works in demo mode
### Customizing Handler Behavior
If generated handler doesn't fit your needs:
1. **Add override** in `src/mocks/handlers/overrides.ts`
2. **Keep generated handler** (don't edit `generated.ts`)
3. **Override takes precedence** automatically
Example:
```typescript
// overrides.ts
export const overrideHandlers = [
// Override auto-generated login to add 2FA simulation
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request }) => {
const body = await request.json();
// Simulate 2FA requirement for admin users
if (body.email.includes('admin') && !body.two_factor_code) {
return HttpResponse.json({ detail: 'Two-factor authentication required' }, { status: 403 });
}
// Fall through to generated handler
}),
];
```
### Updating Mock Data
Mock data is separate from handlers:
```typescript
// src/mocks/data/users.ts
export const demoUser: UserResponse = {
id: 'demo-user-id-1',
email: 'demo@example.com',
first_name: 'Demo',
last_name: 'User',
// ... add more fields as backend evolves
};
```
**To update:**
1. Edit `data/*.ts` files
2. Handlers automatically use updated data
3. No regeneration needed!
## Generator Internals
The generator (`scripts/generate-msw-handlers.ts`) does:
1. **Parse OpenAPI spec**
```typescript
const spec = JSON.parse(fs.readFileSync(specPath, 'utf-8'));
```
2. **For each endpoint:**
- Convert path params: `{id}` → `:id`
- Determine handler category (auth/users/admin)
- Generate appropriate mock response
- Add network delay
- Include error handling
3. **Write generated file:**
```typescript
fs.writeFileSync('src/mocks/handlers/generated.ts', handlerCode);
```
## Troubleshooting
### Generated handler doesn't work
**Check:**
1. Is backend running? (`npm run generate:api` requires backend)
2. Check console for `[MSW]` warnings
3. Verify `generated.ts` exists and has your endpoint
4. Check path parameters match exactly
**Debug:**
```bash
# See what endpoints were generated
cat src/mocks/handlers/generated.ts | grep "http\."
```
### Need custom behavior
**Don't edit `generated.ts`!** Use overrides instead:
```typescript
// overrides.ts
export const overrideHandlers = [
http.post(`${API_BASE_URL}/your/endpoint`, async ({ request }) => {
// Your custom logic
}),
];
```
### Regeneration fails
```bash
# Manual regeneration
cd frontend
curl -s http://localhost:8000/api/v1/openapi.json > /tmp/openapi.json
npx tsx scripts/generate-msw-handlers.ts /tmp/openapi.json
```
## Best Practices
### ✅ Do
- Run `npm run generate:api` after backend changes
- Use `overrides.ts` for complex logic
- Keep mock data in `data/` files
- Test demo mode regularly
- Commit `overrides.ts` to git
### ❌ Don't
- Don't edit `generated.ts` manually (changes will be overwritten)
- Don't commit `generated.ts` to git (it's auto-generated)
- Don't duplicate logic between overrides and generated
- Don't skip regeneration after API changes
## Advanced: Generator Customization
Want to customize the generator itself?
Edit `scripts/generate-msw-handlers.ts`:
```typescript
function generateMockResponse(path: string, method: string, operation: any): string {
// Your custom generation logic
if (path.includes('/your-special-endpoint')) {
return `
// Your custom handler code
`;
}
// ... rest of generation logic
}
```
## Comparison
### Before (Manual)
```typescript
// Had to manually write this for EVERY endpoint:
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request }) => {
// 50 lines of code...
}),
http.get(`${API_BASE_URL}/api/v1/users/me`, async ({ request }) => {
// 30 lines of code...
}),
// ... repeat for 31+ endpoints
// ... manually update when backend changes
// ... easy to forget endpoints
// ... prone to bugs
```
### After (Automated)
```bash
npm run generate:api # Done! All 31+ endpoints handled automatically
```
**Manual Code: 1500+ lines**
**Automated: 1 command**
**Time Saved: Hours per API change**
**Bugs: Near zero (generated from spec)**
---
## See Also
- [DEMO_MODE.md](./DEMO_MODE.md) - Complete demo mode guide
- [API_INTEGRATION.md](./API_INTEGRATION.md) - API client docs
## Summary
**This template is batteries-included.**
Your API client and MSW handlers stay perfectly synchronized with zero manual work.
Just run `npm run generate:api` and everything updates automatically.
That's the power of OpenAPI + automation! 🚀