Get Started
Usage
Reference
Handlers
Suvidha handlers are essential for customizing request processing. They handle validation, responses, and more.
All handlers receive a Conn
object, which contains the following:
req
: An extended Express’Request
object, which includes thecontext
. property for accessing request-specific data added by middlewares.res
: The standard ExpressResponse
object.
/**
* CtxRequest adds context to the Express' Request object
* CtxRequest<Context, Params, ResBody, ReqBody, ReqQuery>,
* Request< Params, ResBody, ReqBody, ReqQuery>
*/
export type Conn<T extends Context, ...> = {
req: CtxRequest<T, ...>;
res: Response;
};
class Suvidha {
constructor(handlers: Handlers);
}
The Suvidha
constructor takes any object that implements the Handlers
interface, which is defined as follows:
export interface Handlers {
onErr(err: unknown, conn: Conn, next: NextFunction): Promise<void> | void;
onSchemaErr(
err: ZodError,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
onComplete(
output: unknown,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
onPostResponse(
outputOrErr: unknown,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
}
Understanding the Handlers
Here’s a breakdown of each handler:
interface Handlers {
onSchemaErr(
err: ZodError,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
// ... other handlers
}
Responsibilities:
- Handles Zod schema validation failures gracefully.
- Typically sends an appropriate error response.
- It can call
next(err)
to delegate error handling to Express’ default error handler or other middleware.
Trigger Conditions:
- This is called when a Zod schema validation fails (e.g., when the request body, query parameters, or path parameters do not match the defined schema).
Arguments:
err
: TheZodError
object containing details about the validation failure.conn
: TheConn
object containing the request (conn.req
) and response (conn.res
) objects.next
: The Express’next
function.
Example implementation:
class CustomHandlers implements Handlers {
onSchemaErr(err: ZodError, conn: Conn, next: NextFunction) {
console.error("Schema validation failed:", err.errors); // Log the errors
conn.res.status(400).json({ error: "Invalid request data" }); // Send a 400 response
}
// ... other handlers
}
interface Handlers {
onErr(err: unknown, conn: Conn, next: NextFunction): Promise<void> | void;
// ... other handlers
}
Responsibilities:
- Handle errors that occur before a response has been sent.
- Can log the error, send an error response, or pass the error to Express’s default error handler using
next(err)
.
Trigger Conditions:
- Called when an error is thrown during middleware or request handler execution before any part of the response has been sent (headers or body).
Arguments:
err
: This can be of any type, depending on what caused the error.conn
: TheConn
object containing the request and response objects.next
: The Expressnext
function.
Example implementation:
class CustomHandlers implements Handlers {
onErr(err: unknown, conn: Conn, next: NextFunction) {
console.error("An error occurred:", err);
conn.res.status(500).json({ error: "Internal server error" }); // Or call next(err)
}
// ... other handlers
}
interface Handlers {
onComplete(
output: unknown,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
// ... other handlers
}
Responsibilities:
- Handles the successful completion of the request handler function when a response has not already been sent.
- Typically send the successful response based on the
output
from the request handler.
Trigger Conditions:
- This is called when the request handler function executes successfully and no part of the response (headers or body) has been sent yet.
Arguments:
output
: The value returned by the request handler function. This can be of any type.conn
: TheConn
object containing the request and response objects.next
: The Expressnext
function. While available, it’s typically not needed inonComplete
.
Example implementation:
class CustomHandlers implements Handlers {
onComplete(output: unknown, conn: Conn, next: NextFunction) {
conn.res.json(output); // Send the output as JSON
}
// ... other handlers
}
interface Handlers {
onPostResponse(
outputOrErr: unknown,
conn: Conn,
next: NextFunction,
): Promise<void> | void;
// ... other handlers
}
Responsibilities:
- Handles anything that happens after a response has been initiated (headers sent). This includes both errors and returned values.
- Log errors that occur after the response has begun.
- Handles the (usually unintentional) scenario where the request handler returns a value after sending a response.
Trigger Conditions:
Methods such as res.send()
and res.json()
, or any other method that
sends headers or a body, are considered equivalent and indicate that the
response has been initiated.
- This is called when something happens after a response has started (headers sent).
This can be:
- Errors thrown by middleware after using
conn.res.send()
. - Errors thrown by the request handler after using
res.send()
. - The request handler returning a value after using
res.send()
. (This is primarily for bug detection).
- Errors thrown by middleware after using
Arguments:
outputOrErr
: Either the error object (if an error occurred) or the returned value from the request handler (if the request handler returned a value after sending the response). The type will beunknown
.conn
: TheConn
object containing the request and response objects.next
: The Expressnext
function. While available, it’s typically not needed inonPostResponse
.
It’s important to note:
- If the request handler throws an error before sending a response,
onErr
is called, notonPostResponse
. - If middleware sends a response, the request handler will not be executed. Any errors thrown by the middleware after sending the response are caught by
onPostResponse
.
Example implementation:
class CustomHandlers implements Handlers {
onPostResponse(outputOrErr: unknown, conn: Conn, next: NextFunction) {
if (outputOrErr instanceof Error) {
// Check if it's an error
console.error("Error after response:", outputOrErr);
// Log the error or perform cleanup tasks.
} else {
console.warn(
"Request handler returned value after sending response:",
outputOrErr,
);
// This is usually a bug. Log it and possibly take corrective action.
}
}
// ... other handlers
}
Example Implementation
class CustomHandlers implements Handlers {
onSchemaErr(err: ZodError, conn: Conn, next: NextFunction) {
console.error("Schema validation failed:", err.errors); // Log the errors
conn.res.status(400).json({ error: "Invalid request data" }); // Send a 400 response
}
onErr(err: unknown, conn: Conn, next: NextFunction) {
console.error("An error occurred:", err);
conn.res.status(500).json({ error: "Internal server error" }); // Or call next(err)
}
onComplete(output: unknown, conn: Conn, next: NextFunction) {
conn.res.json(output); // Send the output as JSON
}
onPostResponse(outputOrErr: unknown, conn: Conn, next: NextFunction) {
if (outputOrErr instanceof Error) {
// Check if it's an error
console.error("Error after response:", outputOrErr);
// You might not be able to send a *new* response here.
// Log the error or perform cleanup tasks.
} else {
console.warn(
"Request handler returned value after sending response:",
outputOrErr,
);
// This is usually a bug. Log it and possibly take corrective action.
}
}
}
// Creating a Suvidha instance with custom handlers
const suvidha = () => new Suvidha(new CustomHandlers());
app.get(
"/reports",
suvidha().handler((req) => {
// Business logic
}),
);