Standardized handling of error responses
Standardized Error Response Handling
Error handling is a core aspect of Koa2 applications. A unified error response format improves API maintainability and allows frontend developers to quickly identify issues. Error standardization includes status code specifications, data structure definitions, and error classification handling.
Basic Structure of Error Response
A standard error response should include three basic fields:
{
"code": 400001,
"message": "Parameter validation failed",
"data": {
"detail": "Username cannot be empty"
}
}
code
: Custom business error code, typically a 6-digit number where the first three digits indicate the error category.message
: Human-readable error description.data
: Optional field containing error details or debugging information.
Error Classification Handling
HTTP Standard Errors
Directly reuse the HTTP status code system:
ctx.status = 404;
ctx.body = {
code: 404000,
message: 'Resource not found'
}
Business Logic Errors
Custom error code range (example):
// User-related errors 400100-400199
const USER_ERRORS = {
INVALID_CREDENTIALS: [400101, 'Incorrect username or password'],
DUPLICATE_EMAIL: [400102, 'Email already registered']
}
throw new BusinessError(USER_ERRORS.INVALID_CREDENTIALS);
System-Level Errors
5xx errors should be logged but not expose details:
app.on('error', (err, ctx) => {
logger.error('server error', err);
ctx.status = 500;
ctx.body = {
code: 500000,
message: 'System busy, please try again later'
}
});
Middleware Implementation
Create an error-handling middleware:
async function errorHandler(ctx, next) {
try {
await next();
} catch (err) {
// Known business errors
if (err instanceof BusinessError) {
ctx.status = 400;
ctx.body = {
code: err.code,
message: err.message,
data: err.data
};
return;
}
// Parameter validation errors
if (err instanceof ParameterError) {
ctx.status = 422;
ctx.body = {
code: 422000,
message: 'Parameter validation failed',
data: err.errors
};
return;
}
// Unknown system errors
ctx.app.emit('error', err, ctx);
}
}
Error Code Specification Design
Use a hierarchical encoding scheme:
400000
├─ 400100 User module errors
│ ├─ 400101 Authentication failed
│ └─ 400102 Insufficient permissions
└─ 400200 Order module errors
├─ 400201 Out of stock
└─ 400202 Payment timeout
Maintain an error code constants file:
// error-codes.js
module.exports = {
USER: {
AUTH_FAILED: [400101, 'Authentication failed'],
PERMISSION_DENIED: [400102, 'Insufficient permissions']
},
ORDER: {
OUT_OF_STOCK: [400201, 'Out of stock'],
PAYMENT_TIMEOUT: [400202, 'Payment timeout']
}
}
Parameter Validation Error Handling
Error transformation when using Joi validation:
const schema = Joi.object({
username: Joi.string().required(),
age: Joi.number().min(18)
});
async function validate(ctx, next) {
try {
const { error, value } = schema.validate(ctx.request.body);
if (error) {
throw new ParameterError('Invalid parameters', error.details);
}
ctx.validatedData = value;
await next();
} catch (err) {
throw err;
}
}
Example output format:
{
"code": 422000,
"message": "Parameter validation failed",
"data": [
{
"path": ["username"],
"message": "Username cannot be empty"
},
{
"path": ["age"],
"message": "Age must be at least 18"
}
]
}
Multilingual Error Messages
Support dynamic message internationalization:
class I18nError extends Error {
constructor(key, data) {
const message = i18n.t(key, data);
super(message);
this.key = key;
this.data = data;
}
}
// Usage example
throw new I18nError('errors.user.not_found', { userId: 123 });
Error Logging Strategy
Log full stack traces in development:
if (process.env.NODE_ENV === 'development') {
ctx.body.stack = err.stack;
}
Production environment logging standards:
logger.error({
type: 'API_ERROR',
code: err.code,
path: ctx.path,
params: ctx.request.body,
stack: err.stack
});
Client-Side Error Handling Example
Frontend handling of standardized error responses:
async function fetchData() {
try {
const res = await axios.get('/api/user');
return res.data;
} catch (err) {
if (err.response) {
const { code, message } = err.response.data;
switch(code) {
case 400101:
showToast(message);
redirectToLogin();
break;
case 500000:
showSystemErrorDialog();
break;
default:
handleCommonError(message);
}
}
}
}
Error Simulation During Testing
Simulate error responses in unit tests:
describe('Error Handling', () => {
it('should return 400 for invalid params', async () => {
const res = await request(app)
.post('/login')
.send({});
expect(res.status).toBe(400);
expect(res.body.code).toBe(400101);
});
});
Mock service example:
nock('https://api.example.com')
.get('/users/1')
.reply(500, {
code: 500001,
message: 'Database connection timeout'
});
Performance Monitoring Integration
Error metric reporting:
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
metrics.increment('api.error', {
code: err.code,
path: ctx.path
});
throw err;
}
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:响应压缩与性能优化
下一篇:MySQL 数据库连接与操作