Skip to content

Add structured error response format across all endpoints #27

Description

@prodbycorne

Overview

Error responses are currently unstructured — some endpoints return { error: '...' }, others return HTML Express default errors, and unhandled exceptions leak stack traces. A consistent error format is required for reliable client-side error handling.

Standard Error Response

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Asset code must be 1–12 uppercase alphanumeric characters",
    "details": {
      "field": "assetCode",
      "received": "xlm!!!",
      "constraint": "regex"
    },
    "request_id": "req_01hx3k..."
  }
}

Error Codes

Code HTTP Meaning
VALIDATION_ERROR 400 Request schema failure
UNAUTHORIZED 401 Missing or invalid API key
NOT_FOUND 404 Resource does not exist
RATE_LIMITED 429 Too many requests
UPSTREAM_ERROR 502 All price sources failed
INTERNAL_ERROR 500 Unexpected server error

Implementation

  1. Create src/errors/AppError.js:
class AppError extends Error {
  constructor(code, message, statusCode, details = {}) { ... }
}
  1. Create central error middleware in src/middleware/errorHandler.js:
function errorHandler(err, req, res, next) {
  const isAppError = err instanceof AppError;
  const status = isAppError ? err.statusCode : 500;
  const code = isAppError ? err.code : 'INTERNAL_ERROR';
  const message = isAppError ? err.message : 'An unexpected error occurred';
  // Never leak err.stack to client in production
  res.status(status).json({ error: { code, message, request_id: req.id } });
}
  1. Attach request_id (nanoid) to every request via middleware.

Acceptance Criteria

  • AppError class created with all codes above
  • Central error handler middleware registered last in Express
  • Stack traces never sent to clients in production
  • request_id on every response (success and error)
  • 404 handler for undefined routes
  • All existing error throws converted to throw new AppError(...)
  • Tests assert error shape for each code

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignapiREST API design and endpoints

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions