Response Format
Last Updated: May 19, 2025
This document describes the standardized API response format used in the Typus Development Framework.
Overview
The Typus Development Framework implements a consistent response format for all API endpoints. This standardization ensures that frontend clients can reliably parse and handle responses, simplifying error handling and data extraction.
The response format is automatically applied by the RouterHelper, which wraps all controller methods and ensures that responses follow the standard structure regardless of the specific controller implementation.
Standard Response Structure
All API responses follow a consistent JSON structure:
{
"status": 200,
"data": { ... },
"error": null
}
For error responses:
{
"status": 400,
"data": null,
"error": {
"message": "Error message",
"code": "ERROR_CODE"
}
}
This structure provides a clear separation between successful responses and errors, making it easy for clients to determine the outcome of a request and handle it appropriately.
Response Processing Flow
The RouterHelper automatically processes controller responses and formats them according to the standard structure:
Success Responses
When a controller method returns data successfully, the RouterHelper automatically wraps it in the standard response format:
- The HTTP status code is set to 200 (or the specified status code)
- The response body includes the status, data, and a null error field
- The content type is set to application/json
Example of a successful response:
{
"status": 200,
"data": {
"id": 123,
"name": "Example Item",
"createdAt": "2025-05-19T10:30:00Z"
},
"error": null
}
Error Responses
When an error occurs, either thrown by a controller method or caught by the RouterHelper, it is formatted into a standardized error response:
- The HTTP status code is set based on the error type (e.g., 400, 401, 403, 404, 500)
- The response body includes the status, a null data field, and an error object
- The error object contains a message and a code
Example of an error response:
{
"status": 404,
"data": null,
"error": {
"message": "User with ID 123 not found",
"code": "NOT_FOUND"
}
}
Error Types and Status Codes
The framework provides several built-in error types that map to specific HTTP status codes:
Error Type | Status Code | Error Code | Description |
---|---|---|---|
BadRequestError | 400 | BAD_REQUEST | Invalid request parameters or body |
ValidationError | 400 | VALIDATION_ERROR | Request validation failed |
UnauthorizedError | 401 | UNAUTHORIZED | Authentication required |
ForbiddenError | 403 | FORBIDDEN | Insufficient permissions |
NotFoundError | 404 | NOT_FOUND | Resource not found |
BaseError | 500 | INTERNAL_ERROR | Generic server error |
Validation Errors
Validation errors include additional information about the specific validation failures:
{
"status": 400,
"data": null,
"error": {
"message": "Validation failed",
"code": "VALIDATION_ERROR",
"errors": [
{
"path": ["body", "email"],
"message": "Invalid email format"
},
{
"path": ["body", "password"],
"message": "Password must be at least 8 characters"
}
]
}
}
Implementation Details
RouterHelper
The RouterHelper is responsible for:
- Wrapping controller methods in a safe handler that catches and processes errors
- Standardizing response formats by ensuring all responses follow the defined structure
- Setting appropriate status codes based on the response or error type
- Logging request and response details for debugging and monitoring
The RouterHelper's safeHandler
function processes the result of controller methods:
- If the result is already in the standard format, it is used as is
- If the result is a direct return value, it is wrapped in the standard format
- If an error is thrown, it is converted to the standard error format
BaseController
The BaseController provides helper methods for creating standardized responses:
success(res, data, status)
- Creates a success responseerror(res, message, code, status)
- Creates an error responsenotFound(res, message)
- Creates a 404 not found responsebadRequest(res, message, code)
- Creates a 400 bad request responseunauthorized(res, message, code)
- Creates a 401 unauthorized responseforbidden(res, message, code)
- Creates a 403 forbidden response
These methods ensure consistent response formatting across all controllers.
Error Handling
The framework uses a centralized error handling approach:
- Typed errors are thrown by services when exceptional conditions occur
- Controller methods can catch and handle specific errors
- RouterHelper catches any uncaught errors and formats them appropriately
- Global error handler catches any errors that escape the RouterHelper
This multi-layered approach ensures that all errors are properly formatted and returned to the client.
Best Practices
Throwing Errors
Services should throw typed errors instead of returning error objects:
// Instead of:
return { error: { message: 'Not found', code: 'NOT_FOUND', status: 404 } };
// Use:
throw new NotFoundError('Resource not found');
Returning Data
Services should return data directly without wrapping in a data object:
// Instead of:
return { data: result };
// Use:
return result;
Controller Methods
Controller methods should focus on:
- Extracting and validating request parameters
- Calling service methods to perform business logic
- Returning the result directly (let RouterHelper handle formatting)
- Catching specific errors only when special handling is needed
Example controller method:
async getUser(req: Request, res: Response) {
const { id } = req.params;
return await this.userService.getUserById(id);
}
Error Context
When throwing errors, include relevant context to help with debugging:
throw new NotFoundError(`User with ID ${id} not found`, { userId: id });
Client Integration
Frontend clients should be designed to handle the standard response format:
- Check the status code to determine if the request was successful
- Extract data from the data field for successful responses
- Handle errors based on the error code and message
- Display appropriate messages to the user based on the error type
Example client-side handling:
async function fetchData(url) {
try {
const response = await fetch(url);
const result = await response.json();
if (result.error) {
// Handle error based on code
switch (result.error.code) {
case 'NOT_FOUND':
// Handle not found
break;
case 'UNAUTHORIZED':
// Handle unauthorized
break;
default:
// Handle other errors
}
throw new Error(result.error.message);
}
return result.data;
} catch (error) {
// Handle fetch or parsing errors
console.error('Error fetching data:', error);
throw error;
}
}
Conclusion
The standardized response format in the Typus Development Framework provides a consistent and predictable API interface. By automatically formatting all responses through the RouterHelper, the framework ensures that clients can rely on a uniform structure for both successful responses and errors.
This approach simplifies client-side integration, improves error handling, and makes the API more maintainable and user-friendly.