Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Zod Schema Validation and Error Handling #8

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/common/middleware/example.ts

This file was deleted.

24 changes: 24 additions & 0 deletions packages/common/middleware/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Request, Response, NextFunction } from 'express';
import { AnyZodObject, ZodError } from 'zod';


/**
* Middleware function to validate incoming request data against a Zod schema.
* If validation passes, it proceeds to the next middleware; otherwise, it responds with a 400 status and validation error details.
* @param schema - A Zod schema object to validate the request data against.
*/
export const validate = (schema: AnyZodObject) => async (req: Request, res: Response, next: NextFunction) => {
try {
await schema.parseAsync(req.body);
return next();
} catch (err) {
if (err instanceof ZodError) {
return res.status(400).json({
status: 'error',
message: 'Validation failed',
errors: err.errors,
});
}
next(err);
}
};
2 changes: 1 addition & 1 deletion packages/recall-api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import http from 'http';
import dayjs from 'dayjs';
import app from './src';
import Logger from '@recall-server/common/logger';
import Logger from '../common/logger';
import process from 'process';
import chalk from 'chalk';
process.setMaxListeners(100);
Expand Down
1 change: 1 addition & 0 deletions packages/recall-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"class-validator": "^0.14.1",
"compression": "^1.7.4",
"cors": "^2.8.5",
"dayjs": "^1.11.11",
"drizzle-orm": "^0.31.2",
"drizzle-zod": "^0.5.1",
"express": "^4.19.2",
Expand Down
7 changes: 6 additions & 1 deletion packages/recall-api/src/express.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express, {
Application, Request, Response, NextFunction
Application, Request, Response,
} from 'express';
import compression from 'compression';
import helmet from 'helmet';
Expand Down Expand Up @@ -77,6 +77,11 @@ export default async ({ app }: { app: Application }) => {
res.status(200).send({ msg: 'This is working' });
});

/**
* API Routes
* Add more versions of the api below
*/

// Redirect errors to specific pages
/**
* This is a 404 redirect error
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'reflect-metadata';
import { Get, JsonController } from "routing-controllers";
import { Get, Post, JsonController, UseBefore } from "routing-controllers";
import { Inject, Service } from "typedi";
import { validate } from '@recall-server/common/middleware/validate';
import UserService from "../services/user.service";
import { RegisterDependency } from "@recall-server/core";
import { userRegistrationSchema } from '../schemas/user.schema';

@Service()
@RegisterDependency()
Expand All @@ -16,4 +18,11 @@ export class UserController {
getUserExample() {
return this.userService.getExample();
}

@Post('/register')
@UseBefore(validate(userRegistrationSchema))
async register(){
// Registration logic
return this.userService.register();
}
}
25 changes: 25 additions & 0 deletions packages/recall-api/src/modules/auth/schemas/user.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { z } from 'zod';

/**
* Defines a Zod object schema for validating user data with the following shape:
* - name: Required string with minimum length of 1 character
* - email: Valid email format string
* - voterCardNumber: String with exactly 8 characters
* - nationalID: String with exactly 8 characters
* - constituencyName: Required string with minimum length of 1 character
* - ward: Required string with minimum length of 1 character
* - pollingStation: Required string with minimum length of 1 character
* - pollingStationNo: Required string with minimum length of 1 character
* - password: String with minimum length of 6 characters
*/
export const userRegistrationSchema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().email('Invalid email format'),
voterCardNumber: z.string().length(8, 'Voter Card Number must be 8 characters'),
nationalID: z.string().length(8, 'National ID must be 8 characters'),
constituencyName: z.string().min(1, 'Constituency Name is required'),
ward: z.string().min(1, 'Ward is required'),
pollingStation: z.string().min(1, 'Polling Station is required'),
pollingStationNo: z.string().min(1, 'Polling Station Number is required'),
password: z.string().min(6, 'Password must be at least 6 characters'),
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export default class UserService {
public getExample() {
return {
message: 'User Basic Example'
}
};
}

public register() {
return {
message: 'Register Registration'
};
}
}
999 changes: 512 additions & 487 deletions yarn.lock

Large diffs are not rendered by default.