-
Notifications
You must be signed in to change notification settings - Fork 57
Add Zod validation middleware to all backend routes — replace manual checks #193
Copy link
Copy link
Open
Labels
BackendStellar WaveIssues in the Stellar wave programIssues in the Stellar wave programsecuritySecurity vulnerability or concernSecurity vulnerability or concern
Description
Description
Some backend routes validate input with Zod schemas, but many routes perform manual checks or no validation at all. Inconsistent validation means some endpoints accept malformed data that causes database errors or unexpected behavior. All routes should use a consistent Zod middleware pattern.
Current Inconsistency
// Some routes — proper Zod validation
const schema = z.object({ name: z.string().min(1), price: z.number().positive() });
const result = schema.safeParse(req.body);
if (\!result.success) return res.status(422).json({ errors: result.error.issues });
// Other routes — no validation
router.post('/', authenticate, async (req, res) => {
const { name, price, billingCycle } = req.body; // ← no validation
await supabase.from('subscriptions').insert({ name, price, billing_cycle: billingCycle });
});Solution: Shared validation middleware factory
/backend/src/middleware/validate.ts
import { ZodSchema } from 'zod';
import { Request, Response, NextFunction } from 'express';
export function validate(schema: ZodSchema, source: 'body' | 'query' | 'params' = 'body') {
return (req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req[source]);
if (\!result.success) {
return res.status(422).json({
type: 'https://syncro.app/errors/validation',
title: 'Validation Error',
status: 422,
errors: result.error.issues.map(i => ({
field: i.path.join('.'),
message: i.message,
})),
});
}
req[source] = result.data; // replace with parsed/coerced data
next();
};
}Usage
const createSubscriptionSchema = z.object({
name: z.string().min(1).max(100),
price: z.number().positive().max(100000),
currency: z.string().length(3),
billing_cycle: z.enum(['monthly', 'quarterly', 'annual', 'weekly']),
next_renewal_date: z.string().datetime(),
renewal_url: z.string().url().max(2000).optional(),
category: z.string().max(50).optional(),
});
router.post('/', authenticate, validate(createSubscriptionSchema), createSubscription);All Routes Needing Schemas
POST /api/subscriptions— createSubscriptionSchemaPUT /api/subscriptions/:id— updateSubscriptionSchemaPOST /api/team/invite— inviteTeamSchemaPOST /api/keys— createApiKeySchemaPOST /api/webhooks— createWebhookSchema- All other POST/PUT endpoints
Acceptance Criteria
-
validate()middleware created and exported - All POST and PUT routes use the middleware
- Validation errors return consistent Problem Details format
- All schemas have explicit max lengths on string fields
- Query parameter validation added to GET routes with filters
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
BackendStellar WaveIssues in the Stellar wave programIssues in the Stellar wave programsecuritySecurity vulnerability or concernSecurity vulnerability or concern