feat: Enhance API validation and error handling across routes
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
- Added tests for invalid request bodies in price and recipe routes. - Improved type safety in request handlers using Zod schemas. - Introduced a consistent validation pattern for empty request bodies. - Enhanced error messages for invalid query parameters in stats and user routes. - Implemented middleware to inject mock logging for tests. - Created a custom type for validated requests to streamline type inference.
This commit is contained in:
@@ -25,7 +25,9 @@ We will adopt a schema-based approach for input validation using the `zod` libra
|
||||
|
||||
3. **Refactor Routes**: All route handlers will be refactored to use this new middleware, removing all manual validation logic.
|
||||
|
||||
### Example Usage
|
||||
4. **(New) Resilient Type Inference**: To achieve full type safety, we will use **inline type assertions** with `z.infer<typeof schema>`. This ensures the code inside the handler is fully typed and benefits from IntelliSense without creating complex utility types that conflict with Express's `RequestHandler` signature.
|
||||
|
||||
### Example Usage (Refined Pattern)
|
||||
|
||||
```typescript
|
||||
// In flyer.routes.ts
|
||||
@@ -33,31 +35,37 @@ We will adopt a schema-based approach for input validation using the `zod` libra
|
||||
import { z } from 'zod';
|
||||
import { validateRequest } from '../middleware/validation';
|
||||
|
||||
// Define the schema for the GET /:id route
|
||||
// 1. Define the schema
|
||||
const getFlyerSchema = z.object({
|
||||
params: z.object({
|
||||
id: z.string().pipe(z.coerce.number().int().positive()),
|
||||
}),
|
||||
});
|
||||
|
||||
// Apply the middleware to the route
|
||||
router.get('/:id', validateRequest(getFlyerSchema), async (req, res, next) => {
|
||||
// 2. Infer the type from the schema for local use
|
||||
type GetFlyerRequest = z.infer<typeof getFlyerSchema>;
|
||||
|
||||
// 3. Apply the middleware and use an inline cast for the request
|
||||
router.get('/:id', validateRequest(getFlyerSchema), (async (req, res, next) => {
|
||||
// Cast 'req' to the inferred type.
|
||||
// This provides full type safety for params, query, and body.
|
||||
const { params } = req as unknown as GetFlyerRequest;
|
||||
|
||||
try {
|
||||
// req.params.id is now guaranteed to be a positive number
|
||||
const flyerId = req.params.id;
|
||||
const flyer = await db.flyerRepo.getFlyerById(flyerId);
|
||||
const flyer = await db.flyerRepo.getFlyerById(params.id); // params.id is 'number'
|
||||
res.json(flyer);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
}));
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
**DRY and Declarative**: Validation logic is defined once in a schema and removed from route handlers.
|
||||
**Reduced Complexity**: Avoids maintaining a complex ValidatedRequestHandler utility type that could conflict with Express or TypeScript upgrades.
|
||||
**Explicit Contracts**: By defining the Request type right next to the route, the contract for that endpoint is immediately visible.
|
||||
**Improved Readability**: Route handlers become much cleaner and focus exclusively on their core business logic.
|
||||
**Type Safety**: `zod` schemas provide strong compile-time and runtime type safety, reducing bugs.
|
||||
**Consistent and Detailed Errors**: The `errorHandler` can be configured to provide consistent, detailed validation error messages for all routes (e.g., "Query parameter 'limit' must be a positive integer").
|
||||
@@ -65,6 +73,7 @@ router.get('/:id', validateRequest(getFlyerSchema), async (req, res, next) => {
|
||||
|
||||
### Negative
|
||||
|
||||
**Minor Verbosity**: Requires one extra line (type ... = z.infer<...>) and a controlled cast (as unknown as ...) within the handler function.
|
||||
**New Dependency**: Introduces `zod` as a new project dependency.
|
||||
**Learning Curve**: Developers need to learn the `zod` schema definition syntax.
|
||||
**Refactoring Effort**: Requires a one-time effort to create schemas and refactor all existing routes to use the `validateRequest` middleware.
|
||||
|
||||
Reference in New Issue
Block a user