Overview
StatusFlow provides flexible options for customizing error responses. This guide shows you how to override default messages, add custom fields, and create tailored response formats for your API.
Customization Options
StatusFlow offers several ways to customize responses:
Override Messages Replace default messages with custom text
Extra Fields Add custom data to response objects
Exception Details Include context with exception details
Success Responses Create uniform success response formats
Overriding Default Messages
Customize the message in your error responses:
Using StatusFlow Function
The overrideMessage parameter replaces the default message:
import { StatusFlow } from 'status-flow' ;
app . get ( '/users/:id' , ( req , res ) => {
const user = database . findUser ( req . params . id );
if ( ! user ) {
const response = StatusFlow ({
code: 404 ,
lang: 'en' ,
overrideMessage: 'The requested user does not exist in our system' ,
});
return res . status ( 404 ). json ( response );
}
res . json ({ success: true , data: user });
});
Response:
{
"code" : 404 ,
"success" : false ,
"message" : "The requested user does not exist in our system" ,
"info" : {
"name" : "Not Found" ,
"category" : "Client Error" ,
"description" : "The requested resource was not found" ,
"possibleCauses" : [
"Incorrect URL" ,
"Resource deleted" ,
"Resource never existed"
]
}
}
Using HTTP Exceptions
Pass a custom message to the exception constructor:
import { NotFoundException , BadRequestException } from 'status-flow' ;
app . post ( '/products/:id/purchase' , ( req , res ) => {
const product = database . findProduct ( req . params . id );
if ( ! product ) {
throw new NotFoundException (
'This product is no longer available for purchase'
);
}
if ( product . stock === 0 ) {
throw new BadRequestException (
'Product is currently out of stock. Please check back later.'
);
}
// Process purchase...
});
Custom messages are especially useful for providing user-friendly error descriptions that make sense in your application’s context.
Include additional data in your responses using the extra parameter:
Basic Usage
import { StatusFlow } from 'status-flow' ;
app . post ( '/orders' , ( req , res ) => {
const { productId , quantity } = req . body ;
const product = database . findProduct ( productId );
if ( ! product ) {
const response = StatusFlow ({
code: 404 ,
lang: 'en' ,
overrideMessage: 'Product not found' ,
extra: {
requestedProductId: productId ,
availableProducts: database . getAvailableProductIds (),
timestamp: new Date (). toISOString (),
},
});
return res . status ( 404 ). json ( response );
}
if ( quantity > product . stock ) {
const response = StatusFlow ({
code: 400 ,
lang: 'en' ,
overrideMessage: 'Insufficient stock' ,
extra: {
requestedQuantity: quantity ,
availableStock: product . stock ,
productName: product . name ,
estimatedRestockDate: product . restockDate ,
},
});
return res . status ( 400 ). json ( response );
}
// Process order...
});
Response:
{
"code" : 400 ,
"success" : false ,
"message" : "Insufficient stock" ,
"requestedQuantity" : 10 ,
"availableStock" : 3 ,
"productName" : "Wireless Mouse" ,
"estimatedRestockDate" : "2026-03-15" ,
"info" : {
"name" : "Bad Request" ,
"category" : "Client Error" ,
"description" : "The request could not be understood or was missing required parameters" ,
"possibleCauses" : [ ... ]
}
}
All fields from the extra object are merged into the top-level response. This makes it easy for clients to access custom data without nesting.
Advanced Example: Validation Errors
Provide detailed validation feedback:
import { StatusFlow } from 'status-flow' ;
app . post ( '/users' , ( req , res ) => {
const { email , password , age } = req . body ;
const errors = [];
if ( ! email || ! email . includes ( '@' )) {
errors . push ({
field: 'email' ,
message: 'Valid email address is required' ,
value: email || null ,
});
}
if ( ! password || password . length < 8 ) {
errors . push ({
field: 'password' ,
message: 'Password must be at least 8 characters' ,
value: password ? '***' : null ,
});
}
if ( age && ( age < 18 || age > 120 )) {
errors . push ({
field: 'age' ,
message: 'Age must be between 18 and 120' ,
value: age ,
});
}
if ( errors . length > 0 ) {
const response = StatusFlow ({
code: 400 ,
lang: 'en' ,
overrideMessage: 'Validation failed' ,
extra: {
validationErrors: errors ,
errorCount: errors . length ,
receivedFields: Object . keys ( req . body ),
},
});
return res . status ( 400 ). json ( response );
}
// Create user...
});
Using Exception Details
When using HTTP exceptions with httpErrorMiddleware, use the details parameter:
import { BadRequestException , NotFoundException , ConflictException } from 'status-flow' ;
app . post ( '/users' , async ( req , res ) => {
const { email , username , password } = req . body ;
// Validation errors with details
if ( ! email || ! username || ! password ) {
throw new BadRequestException (
'Missing required fields' ,
{
required: [ 'email' , 'username' , 'password' ],
received: Object . keys ( req . body ),
missing: [
! email && 'email' ,
! username && 'username' ,
! password && 'password' ,
]. filter ( Boolean ),
}
);
}
// Check for conflicts
const existingEmail = await database . findByEmail ( email );
const existingUsername = await database . findByUsername ( username );
if ( existingEmail || existingUsername ) {
throw new ConflictException (
'User already exists' ,
{
conflicts: {
email: !! existingEmail ,
username: !! existingUsername ,
},
suggestions: {
email: existingEmail ? generateAlternativeEmail ( email ) : null ,
username: existingUsername ? generateAlternativeUsername ( username ) : null ,
},
}
);
}
// Create user...
});
Response:
{
"status" : 409 ,
"message" : "User already exists" ,
"details" : {
"conflicts" : {
"email" : true ,
"username" : false
},
"suggestions" : {
"email" : "[email protected] " ,
"username" : null
}
}
}
Creating Success Responses
StatusFlow provides utilities for uniform success responses:
Using createSuccessResponse
import { createSuccessResponse } from 'status-flow' ;
app . get ( '/users/:id' , async ( req , res ) => {
const user = await database . findUser ( req . params . id );
if ( ! user ) {
throw new NotFoundException ( 'User not found' );
}
const response = createSuccessResponse (
user ,
'User retrieved successfully' ,
200
);
res . json ( response );
});
Response:
{
"status" : 200 ,
"message" : "User retrieved successfully" ,
"data" : {
"id" : "123" ,
"name" : "John Doe" ,
"email" : "[email protected] "
}
}
Custom Success Response Wrapper
Create your own success response format:
function apiResponse < T >( data : T , message = 'Success' , metadata = {}) {
return {
success: true ,
timestamp: new Date (). toISOString (),
message ,
data ,
... metadata ,
};
}
app . get ( '/users' , async ( req , res ) => {
const page = parseInt ( req . query . page as string ) || 1 ;
const limit = parseInt ( req . query . limit as string ) || 10 ;
const { users , total } = await database . getUsersPaginated ( page , limit );
const response = apiResponse (
users ,
'Users retrieved successfully' ,
{
pagination: {
page ,
limit ,
total ,
pages: Math . ceil ( total / limit ),
},
}
);
res . json ( response );
});
Practical Examples
Rate Limiting Response
import { StatusFlow } from 'status-flow' ;
const rateLimiter = ( req : Request , res : Response , next : NextFunction ) => {
const limit = getRateLimit ( req . ip );
if ( limit . exceeded ) {
const response = StatusFlow ({
code: 429 ,
lang: 'en' ,
overrideMessage: 'Rate limit exceeded' ,
extra: {
limit: limit . max ,
remaining: 0 ,
resetAt: limit . resetTime ,
retryAfter: limit . retryAfter ,
},
});
return res . status ( 429 ). json ( response );
}
next ();
};
Authentication Response
import { UnauthorizedException } from 'status-flow' ;
app . post ( '/auth/login' , async ( req , res ) => {
const { email , password } = req . body ;
const user = await database . findByEmail ( email );
const validPassword = user && await bcrypt . compare ( password , user . passwordHash );
if ( ! user || ! validPassword ) {
throw new UnauthorizedException (
'Invalid email or password' ,
{
attemptedEmail: email ,
timestamp: new Date (). toISOString (),
remainingAttempts: getRemainingLoginAttempts ( email ),
lockoutTime: isAccountLocked ( email ) ? getLockoutTime ( email ) : null ,
}
);
}
const token = generateToken ( user );
res . json ({
success: true ,
message: 'Login successful' ,
data: { token , user: sanitizeUser ( user ) },
});
});
Resource Creation Response
import { createSuccessResponse , ConflictException } from 'status-flow' ;
app . post ( '/projects' , async ( req , res ) => {
const { name , description } = req . body ;
const existing = await database . findProjectByName ( name );
if ( existing ) {
throw new ConflictException (
'Project name already exists' ,
{
existingProjectId: existing . id ,
suggestedNames: generateSimilarNames ( name ),
}
);
}
const project = await database . createProject ({ name , description });
const response = createSuccessResponse (
project ,
'Project created successfully' ,
201
);
res . status ( 201 )
. location ( `/projects/ ${ project . id } ` )
. json ( response );
});
Maintenance Mode Response
import { StatusFlow } from 'status-flow' ;
const maintenanceMiddleware = ( req : Request , res : Response , next : NextFunction ) => {
if ( isMaintenanceMode ()) {
const maintenanceInfo = getMaintenanceInfo ();
const response = StatusFlow ({
code: 503 ,
lang: 'en' ,
overrideMessage: 'Service temporarily unavailable for maintenance' ,
extra: {
scheduledEnd: maintenanceInfo . endTime ,
estimatedDuration: maintenanceInfo . duration ,
reason: maintenanceInfo . reason ,
statusPage: 'https://status.example.com' ,
},
});
return res . status ( 503 )
. set ( 'Retry-After' , maintenanceInfo . retryAfter )
. json ( response );
}
next ();
};
Best Practices
Be consistent with response formats
Include helpful debugging information
Don't expose sensitive information
Use language-appropriate messages
Respect the user’s language preference: const lang = req . headers [ 'x-lang' ] === 'en' ? 'en' : 'es' ;
const messages = {
en: 'User not found' ,
es: 'Usuario no encontrado' ,
};
StatusFlow ({
code: 404 ,
lang ,
overrideMessage: messages [ lang ],
});
Provide actionable error messages
Help users understand what to do next: throw new BadRequestException (
'Email format is invalid. Please provide a valid email address like [email protected] ' ,
{ providedEmail: email }
);
Next Steps
TypeScript Usage Type-safe custom responses with TypeScript
StatusFlow API Complete API reference for StatusFlow function
Response Utilities Learn about response helper functions
Error Handling Error handling patterns and best practices