http-smart-response
v1.0.4
Published
Standardized, production-grade HTTP response middleware and helpers for Node.js (Express) and Bun
Maintainers
Readme
http-smart-response
Standardized, production-grade HTTP response middleware and response helper for Node.js (Express) and Bun / Fetch-compatible servers.
http-smart-response guarantees a consistent, structured JSON envelope across your entire API for both successful outputs and error conditions.
Features
- Standardized JSON response templates for success and error states.
- Clean integration with Express via
res.responder.<method>(). - Native Bun and standard Web
Responsesupport viaresponder.<method>(). - Full coverage of production HTTP status codes (2xx, 3xx, 4xx, 5xx).
- Contextual error payload formatting with error codes and validation details.
- Comprehensive TypeScript declarations and typings included out of the box.
Installation
npm install http-smart-response
# or
bun add http-smart-response
# or
yarn add http-smart-response
# or
pnpm add http-smart-responseStandard Response Format
Success Response Envelope
{
"success": true,
"statusCode": 200,
"message": "Resource retrieved successfully",
"data": {
"id": "usr_101",
"name": "Alex Smith"
},
"meta": {
"page": 1,
"total": 100
}
}success(boolean): Alwaystruefor 2xx/3xx codes.statusCode(number): The HTTP status code.message(string): Human-readable status description or custom message.data(any, optional): Main response payload.meta(object, optional): Additional metadata like pagination or tracking headers.
Error Response Envelope
{
"success": false,
"statusCode": 400,
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid request body",
"details": [
{
"field": "email",
"message": "Email must be a valid address"
}
]
}
}success(boolean): Alwaysfalsefor 4xx/5xx codes.statusCode(number): The HTTP status code.error.code(string): Machine-readable error identifier (e.g.BAD_REQUEST,UNAUTHORIZED, or custom).error.message(string): Description of what went wrong.error.details(any, optional): Contextual debugging info or form validation error lists.
Usage
1. Express.js Middleware
Attach responderMiddleware to your Express application. The responder object is automatically mounted to res.responder.
import express from "express";
import { responderMiddleware } from "http-smart-response";
const app = express();
app.use(express.json());
app.use(responderMiddleware());
// 200 OK
app.get("/users/:id", (req, res) => {
const user = { id: req.params.id, name: "Jane Doe" };
return res.responder.ok(user, "User profile retrieved");
});
// 201 Created
app.post("/users", (req, res) => {
const newUser = { id: "usr_99", ...req.body };
return res.responder.created(newUser, "Account created successfully");
});
// 200 / 204 Deletions
app.delete("/users/:id", (req, res) => {
return res.responder.deleted({ id: req.params.id });
});
// 400 Bad Request / Validation Failure
app.post("/login", (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.responder.badRequest("Missing credentials", {
errorCode: "INVALID_CREDENTIALS",
details: { missing: ["email", "password"].filter(f => !req.body[f]) },
});
}
// 401 Unauthorized
if (password !== "secret") {
return res.responder.unauthorized("Invalid email or password");
}
return res.responder.ok({ token: "jwt_sample_token" });
});
// 404 Not Found
app.get("/items/:id", (req, res) => {
return res.responder.notFound("The requested item does not exist", {
errorCode: "ITEM_NOT_FOUND",
});
});
// 500 Internal Server Error
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
return res.responder.internalServerError(err.message, {
errorCode: "INTERNAL_SERVER_ERROR",
});
});
app.listen(3000, () => {
console.log("Server listening on port 3000");
});2. Bun Native HTTP Server
Bun supports web standard Response objects natively. Import the pre-configured responder instance:
import { responder } from "http-smart-response";
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/health") {
return responder.ok({ status: "healthy", uptime: process.uptime() });
}
if (url.pathname === "/api/products" && req.method === "POST") {
return responder.created({ id: 1, name: "Product A" });
}
if (url.pathname === "/api/admin") {
return responder.forbidden("Access denied: Administrator privileges required", {
errorCode: "INSUFFICIENT_PERMISSIONS",
});
}
return responder.notFound("Route not found");
},
});3. Standalone Express Adapter (createResponder)
If you prefer not to register global middleware, you can wrap the Express res object directly:
import express from "express";
import { createResponder } from "http-smart-response";
const app = express();
app.get("/data", (req, res) => {
const r = createResponder(res);
return r.ok({ message: "Hello World" });
});API Method Reference
Success Methods (2xx)
| Method | Status Code | Default Message | Typical Payload |
|---|---|---|---|
| ok(data?, options?) | 200 | "Success" | Any response data |
| created(data?, options?) | 201 | "Resource created successfully" | Newly created entity |
| accepted(data?, options?) | 202 | "Request accepted for processing" | Async task metadata / job ID |
| noContent(headers?) | 204 | Empty body | None |
| deleted(data?, options?) | 200 | "Resource deleted successfully" | Deleted ID or confirmation info |
Redirection Methods (3xx)
| Method | Status Code | Notes |
|---|---|---|
| movedPermanently(url, options?) | 301 | Sets Location header |
| found(url, options?) | 302 | Sets Location header |
| seeOther(url, options?) | 303 | Sets Location header |
| notModified(headers?) | 304 | Empty body |
| temporaryRedirect(url, options?) | 307 | Sets Location header |
| permanentRedirect(url, options?) | 308 | Sets Location header |
Client Error Methods (4xx)
| Method | Status Code | Default Error Code | Description |
|---|---|---|---|
| badRequest(msg?, options?) | 400 | BAD_REQUEST | Malformed syntax or invalid payload |
| unauthorized(msg?, options?) | 401 | UNAUTHORIZED | Authentication missing or failed |
| paymentRequired(msg?, options?) | 402 | PAYMENT_REQUIRED | Subscription or payment needed |
| forbidden(msg?, options?) | 403 | FORBIDDEN | Authenticated but access denied |
| notFound(msg?, options?) | 404 | NOT_FOUND | Resource could not be found |
| methodNotAllowed(msg?, options?) | 405 | METHOD_NOT_ALLOWED | HTTP method not supported for route |
| notAcceptable(msg?, options?) | 406 | NOT_ACCEPTABLE | Requested content negotiation failed |
| requestTimeout(msg?, options?) | 408 | REQUEST_TIMEOUT | Server timed out waiting for request |
| conflict(msg?, options?) | 409 | CONFLICT | State conflict (e.g. duplicate key) |
| gone(msg?, options?) | 410 | GONE | Resource permanently deleted |
| payloadTooLarge(msg?, options?) | 413 | PAYLOAD_TOO_LARGE | Upload or payload exceeds limit |
| unsupportedMediaType(msg?, options?) | 415 | UNSUPPORTED_MEDIA_TYPE | Unsupported Content-Type |
| unprocessableEntity(msg?, options?) | 422 | UNPROCESSABLE_ENTITY | Semantic or schema validation errors |
| tooManyRequests(msg?, options?) | 429 | TOO_MANY_REQUESTS | Rate limit exceeded |
Server Error Methods (5xx)
| Method | Status Code | Default Error Code |
|---|---|---|
| internalServerError(msg?, options?) | 500 | INTERNAL_SERVER_ERROR |
| notImplemented(msg?, options?) | 501 | NOT_IMPLEMENTED |
| badGateway(msg?, options?) | 502 | BAD_GATEWAY |
| serviceUnavailable(msg?, options?) | 503 | SERVICE_UNAVAILABLE |
| gatewayTimeout(msg?, options?) | 504 | GATEWAY_TIMEOUT |
Custom Status Method
| Method | Description |
|---|---|
| custom(statusCode, dataOrMessage?, options?) | Sends a formatted response with any arbitrary HTTP status code. |
Options Interface
Both success and error methods accept optional configuration:
interface ResponderOptions {
message?: string; // Override default description
meta?: Record<string, unknown>; // Metadata (pagination, timestamp, traceId)
errorCode?: string; // Error code string (for 4xx/5xx)
details?: unknown; // Additional error info / validation list
headers?: Record<string, string>; // Custom response headers
}TypeScript Declarations
http-responder extends Express's native Response interface automatically when imported:
declare global {
namespace Express {
interface Response {
responder: ExpressResponder;
}
}
}License
MIT
