阿里云主机折上折
  • 微信号
Current Site:Index > Standardized handling of error responses

Standardized handling of error responses

Author:Chuan Chen 阅读数:48610人阅读 分类: Node.js

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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.