forked from cardosofelipe/fast-next-template
- 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.
405 lines
9.7 KiB
Markdown
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! 🚀
|