Script Valley
REST API Development: Beginner to Production
Data Validation, Error Handling, and API Design PatternsLesson 3.2

Consistent API error response format design

error response envelope, error codes, error messages, stack traces in development, AppError class, centralized error handler, RFC 7807

Consistent Error Response Design

Inconsistent error responses are one of the top complaints API consumers have. Pick a format and stick to it everywhere. RFC 7807 (Problem Details) is a good reference, but even a simple custom envelope works โ€” the key is consistency.

AppError Class

// utils/AppError.js
class AppError extends Error {
  constructor(message, statusCode, code) {
    super(message);
    this.statusCode = statusCode;
    this.code = code; // machine-readable string e.g. 'USER_NOT_FOUND'
    this.isOperational = true; // distinguish from programming errors
  }
}

module.exports = AppError;

Centralized Error Handler

// middleware/errorHandler.js
const AppError = require('../utils/AppError');

module.exports = (err, req, res, next) => {
  const status = err.statusCode || 500;
  const response = {
    error: {
      code: err.code || 'INTERNAL_ERROR',
      message: err.message || 'Something went wrong'
    }
  };
  // Only expose stack in development
  if (process.env.NODE_ENV === 'development') {
    response.error.stack = err.stack;
  }
  res.status(status).json(response);
};
// Usage in controller
throw new AppError('User not found', 404, 'USER_NOT_FOUND');

The isOperational flag distinguishes expected errors (user not found, invalid input) from programming errors (undefined is not a function). Log non-operational errors with full context for debugging; surface only safe messages to clients.

Up next

API pagination โ€” cursor-based vs offset-based

Sign in to track progress

Consistent API error response format design โ€” Data Validation, Error Handling, and API Design Patterns โ€” REST API Development: Beginner to Production โ€” Script Valley โ€” Script Valley