A Hono middleware for standardized JSON responses
return c.json({ code: 2000, data: users, msg: 'Operation successful' });
return c.json({ code: 2000, data: roles, msg: 'Operation successful' });
return c.json({ code: 5000, data: null, msg: 'Username already exists' });
return c.json({ code: 5100, data: null, msg: 'System error' });
return c.ok(users, 'Operation successful');
return c.ok(roles); // No need to pass "Operation successful" every time, as it's the default
return c.bizerr(null, 'Username already exists');
return c.syserr();
- π Unified JSON Response Format - Standardized API response structure
- π― Semantic Response Methods -
c.ok()
is more intuitive thanc.json({code: 2000})
- π§ Eliminate Boilerplate Code - Say goodbye to repetitive
c.json({code: xxx, data: xxx, msg: xxx})
patterns - π Predefined Common Scenarios - ok(success), unauth(unauthorized), bizerr(business error), syserr(system error)
- π οΈ Flexible Extension - Support for custom response methods and status codes
- πͺ Type Safety - Complete TypeScript support and intelligent hints
# npm
npm install hono-json-response
# yarn
yarn add hono-json-response
# pnpm
pnpm add hono-json-response
# bun
bun add hono-json-response
import { Hono } from 'hono';
import { jsonResponse } from 'hono-json-response';
const app = new Hono();
app.use('*', jsonResponse());
app.get('/getUserList', c => {
return c.ok(
{
list: [{ name: 'John' }, { name: 'Jane' }],
totals: 100
},
'Get user list successfully'
);
});
All responses follow a unified JSON format (code, data, msg):
{
"code": 2000,
"data": null,
"msg": ""
}
Support custom response field names to adapt to different project API specifications:
app.use(
'*',
jsonResponse(null, {
code: 'status', // code -> status
data: 'result', // data -> result
msg: 'message' // msg -> message
})
);
Success response
- Status Code: 2000
- Usage: When operation is successful
app.get('/getUserList', c => {
return c.ok(
{
list: [{ name: 'John' }, { name: 'Jane' }],
totals: 100
},
'Get user list successfully'
);
});
Unauthorized response
- Status Code: 4000
- Usage: When user is not logged in or token is invalid
app.post('/login', c => {
return c.unauth();
});
Business error response
- Status Code: 5000
- Usage: Business logic errors (such as duplicate accounts, insufficient inventory, etc.)
app.post('/register', async c => {
const { name } = await c.req.json();
return c.bizerr({ name }, `Username ${name} already exists`);
});
System error response
- Status Code: 5100
- Usage: System-level errors (such as database connection failure, processing exceptions, etc.)
app.post('/foo', c => {
try {
// do something
} catch (error) {
return c.syserr(error);
}
});
Custom response code
- Parameter: code - Custom status code
- Usage: Some complex interfaces may need to return more status codes to represent different business logic
app.get('/orders/:id', async c => {
const orderId = c.req.param('id');
try {
const order = await getOrderById(orderId);
// Order not found
if (!order) {
return c.jr(5000, null, 'Order not found');
}
// No permission to access other user's order
if (order.userId !== userId) {
return c.jr(5001, null, 'No permission to access this order');
}
// Order has been deleted
if (order.status === 'deleted') {
return c.jr(5002, null, 'Order has been deleted');
}
// More business logic...
return c.ok(order, 'Get order details successfully');
} catch (error) {
return c.syserr(null, 'Failed to get order details');
}
});
app.use(
'*',
jsonResponse({
ok: { code: 20000, defaultMsg: 'Override ok' },
unauth: { code: 40000, defaultMsg: 'Override unauth' }
})
);
import type { JSONResponseHandler } from 'hono-json-response';
// Don't forget to use TypeScript module augmentation to extend Context type
declare module 'hono' {
interface Context {
warning: JSONResponseHandler;
forbidden: JSONResponseHandler;
}
}
app.use(
'*',
jsonResponse({
warning: { code: 2001, defaultMsg: 'Warning message' },
forbidden: { code: 4001, defaultMsg: 'Access forbidden' }
})
);
app.get('/warning', c => {
return c.warning(data, 'API will be deprecated');
});
When custom method status codes conflict with default methods, default methods will be automatically removed:
app.use(
'*',
jsonResponse({
mySuccess: { code: 2000 } // Conflicts with default ok method
})
);
// At this point, c.ok method is no longer available, only c.mySuccess is available
Copyright (c) 2025-present, Zhifeng (Jeff) Wang