Using and Extending Suvidha’s Default Handlers
Suvidha’s default handlers offer a quick start for request/response management. They handle common tasks and can be easily extended.
Introduction
Default handlers provide a pre-configured setup. They handle response formatting, errors, and successful requests, allowing you to focus on your logic. They’re ready to use yet customizable.
Basic Usage
import express from "express" ;
import { Suvidha , DefaultHandlers , Http } from "suvidha" ;
const app = express ();
app . use ( express . json ());
const suvidha = () => Suvidha . create ( new DefaultHandlers ());
app . get (
"/hello" ,
suvidha (). handler (() => {
return Http . Ok . body ({ message: "Hello, world!" });
}),
);
// Example using a plain Protocol object:
app . get (
"/simple" ,
suvidha (). handler (() => {
return { status: 200 , body: { message: "This is simple." } };
}),
);
app . listen ( 3000 , () => console . log ( "Server listening on port 3000" ));
Default handlers are created with new DefaultHandlers()
. suvidha()
uses them to process requests. Your handler function contains your logic. Return data, use Http
classes, or plain Protocol
objects for responses.
Extending
Extend the default handlers to customize behavior. Create a class that inherits from DefaultHandlers
and overrides its methods.
import { Handlers , Conn } from "suvidha" ;
import { DefaultHandlers } from "./defaultHandlers" ;
export class SimpleCustomHandlers extends DefaultHandlers implements Handlers {
override onComplete ( output : unknown , conn : Conn , next : NextFunction ) {
// Add custom headers to all responses
conn . res . setHeader ( "X-API-Version" , "2.0" );
// Preserve default behavior
super . onComplete ( output , conn , next );
}
override onErr ( err : unknown , conn : Conn , next : NextFunction ) {
// Simple error logging
console . error ( "[Custom Handler Error]" , err );
// Custom error format
conn . res . status ( 500 ). json ({
error: "Something went wrong" ,
reference: Date . now (). toString ( 36 ),
});
}
}
User Profile Endpoint with SimpleCustomHandlers
app . get (
"/users/:id" ,
Suvidha . create ( new SimpleCustomHandlers ())
. params ( z . object ({ id: z . string (). uuid () }))
. use ( async ( req ) => {
const user = await getUser ( req . params . id );
if ( ! user ) throw Http . NotFound . body ( "User not found" );
return { user };
})
. handler (( req ) => {
return {
id: req . context . user . id ,
name: req . context . user . name ,
stats: {
logins: req . context . user . loginCount ,
},
};
}),
);
Successful Response Error Response {
"status" : "success" ,
"data" : {
"id" : "usr_987" ,
"name" : "Alice Smith" ,
"stats" : {
"logins" : 42
}
},
"meta" : {}
}
HTTP / 1.1 200 OK
X-API-Version : 2.0
{
"status" : "success" ,
"data" : {
"id" : "usr_987" ,
"name" : "Alice Smith" ,
"stats" : {
"logins" : 42
}
},
"meta" : {}
}
HTTP / 1.1 200 OK
X-API-Version : 2.0
{
"error" : "Something went wrong" ,
"reference" : "k7gfy2"
}
HTTP / 1.1 500 Internal Server Error
X-API-Version : 2.0
Customization
Logging
Override onComplete
or onErr
.
class MyHandlers extends DefaultHandlers {
override onComplete (
output : unknown ,
conn : Conn ,
next : NextFunction ,
) : Promise < void > | void {
console . log (
`Request completed. Output: ${ JSON . stringify ( output ) } , URL: ${ conn . req . originalUrl } ` ,
);
return super . onComplete ( output , conn , next );
}
override onErr (
err : unknown ,
conn : Conn ,
next : NextFunction ,
) : Promise < void > | void {
console . error ( `Error: ${ err } , URL: ${ conn . req . originalUrl } ` );
return super . onErr ( err , conn , next );
}
}
Override onComplete
or onErr
.
class MyHandlers extends DefaultHandlers {
override onComplete (
output : unknown ,
conn : Conn ,
next : NextFunction ,
) : Promise < void > | void {
conn . res . setHeader ( "Cache-Control" , "no-cache" );
conn . res . setHeader ( "X-API-Version" , "2.0" );
return super . onComplete ( output , conn , next );
}
}
Using next(err)
(Within Suvidha Handlers)
Suvidha handlers receive the next
function, allowing you to pass errors to Express.js error handling middleware or the default Express.js error handler. This is particularly useful if you have existing error handling logic in Express.js that you want to leverage.
import { DefaultHandlers , Conn , Http } from "suvidha" ;
class MyHandlers extends DefaultHandlers {
override onErr (
err : unknown ,
conn : Conn ,
next : NextFunction ,
) : Promise < void > | void {
if ( err instanceof Http . End ) {
return super . onErr ( err , conn , next ); // Default Suvidha error handling
}
return next ( err ); // Delegate to Express.js error handling
}
}
Custom Error Handling
Override onErr
.
import { Http } from "suvidha" ; // Import Http
class MyHandlers extends DefaultHandlers {
override onErr (
err : unknown ,
conn : Conn ,
next : NextFunction ,
) : Promise < void > | void {
if ( err instanceof Http . NotFound ) {
return void conn . res
. status ( 404 )
. send ({ error: "Resource not found" });
} else if (
err instanceof Error &&
err . message . includes ( "Database Error" )
) {
return void conn . res
. status ( 500 )
. send ({ error: "Database error occurred." });
}
return super . onErr ( err , conn , next );
}
}
Override the formatter.
class MyHandlers extends DefaultHandlers {
constructor () {
const fmt = ( status , body , meta ) => {
return {
statusCode: status ,
data: body ,
metadata: meta ,
};
};
super ( fmt );
}
}
Middleware Integration
Use Suvidha’s .use()
method for middleware, which preserves type safety and allows context propagation.
import { Suvidha , DefaultHandlers , Http } from "suvidha" ;
import { z } from "zod" ; // Import Zod
interface User {
id : string ;
role : string ;
}
declare function authenticate ( req : Request ) : Promise < User >;
const suvidha = () => Suvidha . create ( new DefaultHandlers ());
const auth = () =>
suvidha (). use ( async ( req ) => {
const user = await authenticate ( req ). catch (( _ ) => {
throw new Http . Unauthorized ();
});
return { user };
});
const adminOnly = () =>
auth (). use ( async ( req ) => {
if ( req . context . user . role !== "admin" ) {
throw new Http . Forbidden ();
}
return {};
});
const userSchema = z . object ({
name: z . string (),
email: z . string (). email (),
});
const createUser = ( user : User ) => Http . Created . body ( user );
app . post (
"/users" ,
auth ()
. body ( userSchema )
. handler (( req ) => {
const user = req . body ;
return createUser ( user );
}),
);
const pageSchema = z . object ({
page: z . string (). transform ( Number ),
limit: z . string (). transform ( Number ),
});
app . get (
"/users" ,
auth ()
. query ( pageSchema )
. handler (( req ) => {
const { page , limit } = req . query ;
return Http . Ok . body ({ page , limit });
}),
);
app . listen ( 3000 , () => console . log ( "Server is listening on port 3000" )); // Added a port and listen call