Get the FREE Ultimate OpenClaw Setup Guide →

api-error-handling

Scanned
npx machina-cli add skill secondsky/claude-skills/api-error-handling --openclaw
Files (1)
SKILL.md
2.8 KB

API Error Handling

Implement robust error handling with standardized responses and proper logging.

Standard Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request parameters",
    "status": 400,
    "requestId": "req_abc123",
    "timestamp": "2025-01-15T10:30:00Z",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  }
}

Error Class (Node.js)

class ApiError extends Error {
  constructor(code, message, status = 500, details = null) {
    super(message);
    this.code = code;
    this.status = status;
    this.details = details;
  }

  static badRequest(message, details) {
    return new ApiError('BAD_REQUEST', message, 400, details);
  }

  static notFound(resource) {
    return new ApiError('NOT_FOUND', `${resource} not found`, 404);
  }

  static unauthorized() {
    return new ApiError('UNAUTHORIZED', 'Authentication required', 401);
  }
}

// Global error handler
app.use((err, req, res, next) => {
  const status = err.status || 500;
  const response = {
    error: {
      code: err.code || 'INTERNAL_ERROR',
      message: status === 500 ? 'Internal server error' : err.message,
      status,
      requestId: req.id
    }
  };

  if (err.details) response.error.details = err.details;
  if (status >= 500) logger.error(err);

  res.status(status).json(response);
});

Circuit Breaker Pattern

class CircuitBreaker {
  constructor(threshold = 5, timeout = 30000) {
    this.failures = 0;
    this.threshold = threshold;
    this.timeout = timeout;
    this.state = 'CLOSED';
  }

  async call(fn) {
    if (this.state === 'OPEN') throw new Error('Circuit open');
    try {
      const result = await fn();
      this.failures = 0;
      return result;
    } catch (err) {
      this.failures++;
      if (this.failures >= this.threshold) {
        this.state = 'OPEN';
        setTimeout(() => this.state = 'HALF_OPEN', this.timeout);
      }
      throw err;
    }
  }
}

Additional Implementations

See references/python-flask.md for:

  • Python Flask error handling with custom exceptions
  • Circuit breaker with automatic recovery
  • Retry with exponential backoff
  • Sentry integration

Best Practices

  • Use consistent error format across all endpoints
  • Include request IDs for traceability
  • Log errors at appropriate severity levels
  • Never expose stack traces to clients
  • Distinguish client errors (4xx) from server errors (5xx)
  • Provide actionable error messages

Source

git clone https://github.com/secondsky/claude-skills/blob/main/plugins/api-error-handling/skills/api-error-handling/SKILL.mdView on GitHub

Overview

Implements a standardized error response format for APIs, with a reusable ApiError class and a global error handler. This approach improves traceability, user-friendly messaging, and consistent logging across endpoints.

How This Skill Works

Developers create ApiError instances (or use helpers like badRequest, notFound, unauthorized) to represent failures with code, message, status, and optional details. The global error handler then formats a consistent payload (including requestId and timestamp) and sends it with the appropriate HTTP status, while logging as needed. The included circuit breaker example demonstrates guarding risky calls to prevent cascading failures.

When to Use It

  • Building production APIs that require a consistent, client-friendly error payload
  • Implementing centralized logging and request tracing with a unique requestId
  • Guarding external/downstream calls with a circuit breaker pattern
  • Delivering actionable error messages without leaking internals
  • Integrating with error monitoring tools and logging pipelines

Quick Start

  1. Step 1: Create ApiError class with helpers (badRequest, notFound, unauthorized)
  2. Step 2: Add a global error-handling middleware that formats and returns the error payload
  3. Step 3: Wrap risky operations with a CircuitBreaker and log using a requestId

Best Practices

  • Use a consistent error format across all endpoints
  • Include a requestId for end-to-end traceability
  • Log errors at appropriate severity levels (info/warning for 4xx, error for 5xx)
  • Never expose stack traces or internal details to clients
  • Differentiate 4xx (client) from 5xx (server) errors and tailor messages

Example Use Cases

  • Return 400 with a detailed invalid parameter list using ApiError.badRequest with details
  • Return 404 when a resource is not found using ApiError.notFound('Resource')
  • Return 401 when authentication is missing using ApiError.unauthorized()
  • Centralized global error handler includes requestId and standardized payload
  • Wrap flaky external calls with a CircuitBreaker to avoid cascading failures

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers