Chain middleware like LEGO blocks, with type inferred context
propagation.
Data Validation
Zod-powered type safety for body, params, and queries—without cluttering
your routes.
Framework Independence
Keep your business logic clean. No Express.js baggage.
Explicit Control
Fine-grained control over request/response lifecycle.
is a lightweight,
type-safe Express.js library that adds powerful validation, middleware context
management, and response handling.
A utility class for building Express.js route handlers with built-in
data validation and middleware support. It allows you to define Zod
schemas for request parameters, body, and query, and chain middleware
functions that can enrich the request context.
No Rewrites - Adopt incrementally in existing Express apps.
TypeScript Native - Inferred types end “guess what’s in req” games.
import express from "express";import { Suvidha, DefaultHandlers, Formatter } from "suvidha";import { UserSchema } from "./dto";import { authenticate, roleCheck } from "./middlewares";import { createUserHandler } from "./controller";const app = express();app.use(express.json());// Configure Suvidha with default handlersconst suvidha = () => Suvidha.create(new DefaultHandlers());// Protected user creation endpointapp.post( "/users", suvidha() .use(authenticate) .use(roleCheck) // check permissions .body(UserSchema) // Validate request body .handler(async (req) => { // All validation/security passed const newUser = req.body; // type of newUser: z.infer<typeof UserSchema> const { role } = req.context.user; // type of role: string return createUserHandler(newUser, role); // Execute business logic }),);app.listen(3000);
Copy
import express from "express";import { Suvidha, DefaultHandlers, Formatter } from "suvidha";import { UserSchema } from "./dto";import { authenticate, roleCheck } from "./middlewares";import { createUserHandler } from "./controller";const app = express();app.use(express.json());// Configure Suvidha with default handlersconst suvidha = () => Suvidha.create(new DefaultHandlers());// Protected user creation endpointapp.post( "/users", suvidha() .use(authenticate) .use(roleCheck) // check permissions .body(UserSchema) // Validate request body .handler(async (req) => { // All validation/security passed const newUser = req.body; // type of newUser: z.infer<typeof UserSchema> const { role } = req.context.user; // type of role: string return createUserHandler(newUser, role); // Execute business logic }),);app.listen(3000);
Copy
import { Http } "suvidha";import { UserDTO } from "./dto";declare function createUser( user: UserDTO, role: string,): Promise<{ id: string }>;// Core business logic handlerexport async function createUserHandler(user: UserDTO, role: string) { try { const result = await createUser(user, role); // return "body with HTTP 201 Created status" return Http.Created.body(result); } catch (err: any) { if (err.code === "DUPLICATE_EMAIL") { // throw "body with HTTP 409 Conflict status" throw Http.Conflict.body({ message: "Email already exists", }); } throw err; }}
Copy
import { Http, CtxRequest } from "suvidha";type User = { role: string };// Mock authentication serviceconst verify = async (token: string): Promise<User> => { // Replace with real auth logic return { role: "admin" };};// Middlewares add data to the context, which will be available// to all subsequent middlewares and handlersexport const authenticate = async (req: CtxRequest) => { const token = req.headers["authorization"]!; const user = await verify(token).catch((_) => { throw new Http.Unauthorized(); // Convert auth failures to 401 }); return { user }; // add `{ user }` to context};// Role guard: Requires admin privileges// This middleware expects { user: User } in the contextexport const roleCheck = (req: CtxRequest<{ user: User }>) => { if (req.context.user.role !== "admin") { throw Http.Forbidden.body({ message: "Admin access required" }); } return {}; // Nothing to add to the context};
Copy
// data transfer objectsimport { z } from "zod";// User validation schemaexport const UserSchema = z.object({ username: z.string().min(3), email: z.string().email(), age: z.number().min(13),});export type UserDTO = z.infer<typeof UserSchema>;