Skip to content

Commit 40cac89

Browse files
committed
Enhance API documentation and validation using Zod
- Added automatic validation with Zod for Fastify routes, eliminating manual validation. - Updated API documentation for `/api/db/status`, `/api/db/setup`, and user registration endpoints to include detailed descriptions, request bodies, and response schemas. - Implemented Zod schemas for request and response validation in `loginEmail`, `registerEmail`, and `dbSetup` routes. - Improved error handling and response structures for better clarity and consistency. - Removed redundant manual validation logic from route handlers, relying on Fastify's built-in validation.
1 parent 161b0bf commit 40cac89

File tree

7 files changed

+1206
-65
lines changed

7 files changed

+1206
-65
lines changed

services/backend/API_DOCUMENTATION.md

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,19 @@ To add OpenAPI documentation to your routes, define your request body and respon
9090

9191
Make sure you have `zod` and `zod-to-json-schema` installed in your backend service.
9292

93+
### Recommended Approach: Automatic Validation with Zod
94+
95+
The power of Zod lies in providing **automatic validation** through Fastify's schema system. This approach eliminates manual validation and leverages Zod's full validation capabilities.
96+
9397
```typescript
9498
import { z } from 'zod';
9599
import { zodToJsonSchema } from 'zod-to-json-schema';
96100

97101
// 1. Define your Zod schemas for request body, responses, etc.
98102
const myRequestBodySchema = z.object({
99103
name: z.string().min(3).describe("The name of the item (min 3 chars)"),
100-
count: z.number().positive().describe("How many items (must be positive)")
104+
count: z.number().positive().describe("How many items (must be positive)"),
105+
type: z.enum(['mysql', 'sqlite']).describe("Database engine type")
101106
});
102107

103108
const mySuccessResponseSchema = z.object({
@@ -134,24 +139,91 @@ const routeSchema = {
134139
}
135140
};
136141

137-
// 3. Use the schema in your Fastify route definition
138-
fastify.post('/your-route', { schema: routeSchema }, async (request, reply) => {
139-
// Your route handler logic here
140-
// Fastify will automatically validate request.body against myRequestBodySchema
141-
142-
// Example of returning a success response:
143-
// return reply.status(200).send({
144-
// success: true,
145-
// itemId: 'some-uuid-v4-here',
146-
// message: 'Item processed successfully.'
147-
// });
148-
149-
// Example of returning an error response:
150-
// return reply.status(400).send({ success: false, error: "Invalid name provided." });
151-
});
142+
// 3. Use the schema in your Fastify route definition with proper TypeScript typing
143+
interface RequestBody {
144+
name: string;
145+
count: number;
146+
type: 'mysql' | 'sqlite';
147+
}
148+
149+
fastify.post<{ Body: RequestBody }>(
150+
'/your-route',
151+
{ schema: routeSchema },
152+
async (request, reply) => {
153+
// ✅ Fastify has already validated request.body using our Zod schema
154+
// ✅ If we reach here, request.body is guaranteed to be valid
155+
// ✅ No manual validation needed!
156+
157+
const { name, count, type } = request.body; // Fully typed and validated
158+
159+
// Your route handler logic here
160+
return reply.status(200).send({
161+
success: true,
162+
itemId: 'some-uuid-v4-here',
163+
message: `Item ${name} processed successfully with ${count} items using ${type}.`
164+
});
165+
}
166+
);
167+
```
168+
169+
### Key Benefits of This Approach
170+
171+
1. **Single Source of Truth**: Zod schemas define both validation AND documentation
172+
2. **Automatic Validation**: Fastify automatically validates requests before your handler runs
173+
3. **No Manual Validation**: Remove all manual `zod.parse()` calls and field checks
174+
4. **Better Error Messages**: Fastify provides detailed validation errors automatically
175+
5. **Type Safety**: Handlers receive properly typed, validated data
176+
6. **Cleaner Code**: No redundant validation logic in handlers
177+
178+
### What NOT to Do (Anti-patterns)
179+
180+
**Don't do manual validation in handlers:**
181+
```typescript
182+
// BAD: Manual validation (redundant)
183+
const parsedBody = myRequestBodySchema.safeParse(request.body);
184+
if (!parsedBody.success) {
185+
return reply.status(400).send({ error: 'Invalid request body' });
186+
}
187+
188+
// BAD: Manual field checks (redundant)
189+
if (!request.body.name || !request.body.count) {
190+
return reply.status(400).send({ error: 'Required fields missing' });
191+
}
192+
193+
// BAD: Manual enum validation (redundant)
194+
if (request.body.type !== 'mysql' && request.body.type !== 'sqlite') {
195+
return reply.status(400).send({ error: 'Invalid database type' });
196+
}
152197
```
153198

154-
**Note**: Older examples in this document (like the "Logout Route Documentation" below) might still show manually crafted JSON schemas. The recommended approach is now to use Zod with `zod-to-json-schema` as shown above for better type safety and maintainability.
199+
**Do trust Fastify's automatic validation:**
200+
```typescript
201+
// GOOD: Trust the validation - if handler runs, data is valid
202+
const { name, count, type } = request.body; // Already validated by Fastify
203+
```
204+
205+
### Validation Flow
206+
207+
The validation chain works as follows:
208+
209+
**Zod Schema → JSON Schema → Fastify Validation → Handler**
210+
211+
1. **Zod Schema**: Define validation rules using Zod
212+
2. **JSON Schema**: Convert to OpenAPI format using `zodToJsonSchema()`
213+
3. **Fastify Validation**: Fastify automatically validates incoming requests
214+
4. **Handler**: Receives validated, typed data
215+
216+
If validation fails, Fastify automatically returns a 400 error **before** your handler runs.
217+
218+
### Real-World Examples
219+
220+
See these files for complete examples of proper Zod validation:
221+
- `src/routes/db/setup.ts` - Database setup with enum validation
222+
- `src/routes/db/status.ts` - Simple GET endpoint with response schemas
223+
- `src/routes/auth/loginEmail.ts` - Login with required string fields
224+
- `src/routes/auth/registerEmail.ts` - Registration with complex validation rules
225+
226+
**Note**: Older examples in this document (like the "Logout Route Documentation" below) might still show manually crafted JSON schemas. The recommended approach is now to use Zod with automatic Fastify validation as shown above.
155227

156228
## Example: Logout Route Documentation
157229

0 commit comments

Comments
 (0)