Skip to content

Latest commit

 

History

History
311 lines (253 loc) · 8.8 KB

File metadata and controls

311 lines (253 loc) · 8.8 KB

Standardized Error Envelope Implementation Summary

Overview

This document summarizes the implementation of standardized error and success envelopes across all API routes in the Fluxora Backend. The goal was to ensure consistent response structures for both successful and error responses, making the API more predictable and easier to consume.

Changes Made

1. Updated Response Utilities (src/utils/response.ts)

Before:

export interface ErrorEnvelope {
    success: false;
    error: string;
    code: string;
    details?: string;
    field?: string;
}

export function errorResponse(
    error: string,
    code: string,
    details?: string,
    field?: string
): ErrorEnvelope

After:

export interface ErrorDetail {
    code: string;
    message: string;
    details?: unknown;
    requestId?: string;
}

export interface ErrorEnvelope {
    success: false;
    error: ErrorDetail;
}

export function errorResponse(
    code: string,
    message: string,
    details?: unknown,
    requestId?: string
): ErrorEnvelope

Key Changes:

  • Restructured error envelope to nest error details under error property
  • Changed parameter order to code, message, details, requestId for consistency
  • Made details type more flexible (unknown instead of string)
  • Added requestId support for better debugging

2. Updated Error Handler Middleware (src/middleware/errorHandler.ts)

Changes:

  • Imported errorResponse helper from utils/response.ts
  • Updated all error responses to use the standardized errorResponse() function
  • Ensured consistent error envelope structure across all error types:
    • DecimalSerializationError
    • ApiError
    • entity.too.large errors
    • Unexpected errors

Example:

// Before
res.status(400).json({
  error: {
    code: ApiErrorCode.DECIMAL_ERROR,
    message: err.message,
    details: { decimalErrorCode: err.code, field: err.field },
    requestId,
  },
});

// After
res.status(400).json(
  errorResponse(
    ApiErrorCode.DECIMAL_ERROR,
    err.message,
    { decimalErrorCode: err.code, field: err.field },
    requestId
  )
);

3. Updated All Route Files

src/routes/streams.ts

  • Imported successResponse helper
  • Wrapped all successful responses in successResponse():
    • Stream listing (GET /api/streams)
    • Stream retrieval (GET /api/streams/:id)
    • Stream creation (POST /api/streams)
    • Stream cancellation (DELETE /api/streams/:id)
  • Ensured requestId is passed to all response helpers

src/routes/health.ts

  • Already using successResponse and errorResponse
  • No changes needed

src/routes/audit.ts

  • Imported successResponse helper
  • Wrapped audit log response in successResponse()
  • Added requestId support

src/routes/dlq.ts

  • Imported successResponse and errorResponse helpers
  • Updated all responses to use standardized envelopes:
    • DLQ listing (GET /admin/dlq)
    • DLQ entry retrieval (GET /admin/dlq/:id)
    • DLQ entry deletion (DELETE /admin/dlq/:id)
    • Operator role enforcement errors
  • Replaced inline validation errors with validationError() helper

src/routes/indexer.ts

  • Imported successResponse helper
  • Wrapped indexer ingestion response in successResponse()

src/routes/webhooks.ts

  • Imported successResponse and errorResponse helpers
  • Updated all webhook endpoints:
    • Delivery status (GET /api/webhooks/deliveries/:deliveryId)
    • Delivery listing (GET /api/webhooks/deliveries)
    • Signature verification (POST /api/webhooks/verify)
    • Retry processing (POST /internal/webhooks/retry)

src/app.ts

  • Imported successResponse and errorResponse helpers
  • Updated root endpoint (GET /) to use successResponse()
  • Updated 404 handler to use errorResponse()

4. Updated Test Files

tests/helpers.test.ts

  • Added comprehensive tests for successResponse() and errorResponse() helpers
  • Tests cover:
    • Success envelope structure
    • Error envelope structure
    • Optional fields (requestId, details)
    • Different data types
    • Envelope consistency

tests/routes/streams.test.ts

  • Updated all test assertions to expect standardized envelope structure
  • Changed from res.body.field to res.body.data.field for success responses
  • Changed from res.body.error to res.body.error.message for error responses
  • Added success field assertions

tests/routes/health.test.ts

  • Updated test assertions to expect standardized envelope structure
  • Changed from res.body.field to res.body.data.field
  • Changed from res.body.timestamp to res.body.meta.timestamp

5. Updated Documentation

API_BEHAVIOR.md

  • Updated all HTTP status code examples to show standardized envelope structure
  • Updated error response format section
  • Changed error codes from snake_case to UPPER_SNAKE_CASE
  • Added success response structure documentation
  • Updated all failure mode examples

openapi.yaml

  • Added SuccessResponse schema definition
  • Updated ErrorResponse schema to match new structure
  • Removed status field from error response (redundant with HTTP status code)
  • Changed error codes to UPPER_SNAKE_CASE
  • Added success field to both schemas

Response Structure

Success Response

{
  "success": true,
  "data": {
    // Response payload
  },
  "meta": {
    "timestamp": "2024-01-01T12:00:00.000Z",
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Error Response

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Human-readable error message",
    "details": {
      // Optional additional context
    },
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}

Benefits

  1. Consistency: All API responses follow the same structure
  2. Type Safety: TypeScript interfaces ensure compile-time correctness
  3. Debugging: requestId in every response enables log correlation
  4. Client-Friendly: success field allows easy response type detection
  5. Extensibility: details field supports arbitrary error context
  6. Standards Compliance: Follows REST API best practices

Breaking Changes

⚠️ This is a breaking change for API clients

Clients must update their response parsing logic:

Before:

// Success
const streamId = response.id;
const timestamp = response.timestamp;

// Error
const errorCode = response.error.code;

After:

// Success
if (response.success) {
  const streamId = response.data.id;
  const timestamp = response.meta.timestamp;
}

// Error
if (!response.success) {
  const errorCode = response.error.code;
}

Migration Guide for Clients

  1. Check the success field to determine response type
  2. Access data through response.data for successful responses
  3. Access metadata through response.meta (timestamp, requestId)
  4. Access error details through response.error for error responses
  5. Update error code comparisons to use UPPER_SNAKE_CASE

Testing

All tests have been updated to verify:

  • ✅ Success responses have correct envelope structure
  • ✅ Error responses have correct envelope structure
  • requestId is included when available
  • timestamp is valid ISO-8601 format
  • success field correctly indicates response type
  • ✅ Decimal string serialization guarantees are preserved

Files Modified

Source Files

  • src/utils/response.ts - Response envelope helpers
  • src/middleware/errorHandler.ts - Error handler middleware
  • src/routes/streams.ts - Streams API routes
  • src/routes/audit.ts - Audit log routes
  • src/routes/dlq.ts - Dead-letter queue routes
  • src/routes/indexer.ts - Indexer routes
  • src/routes/webhooks.ts - Webhook routes
  • src/app.ts - Application setup and 404 handler

Test Files

  • tests/helpers.test.ts - Response envelope helper tests
  • tests/routes/streams.test.ts - Streams route tests
  • tests/routes/health.test.ts - Health route tests

Documentation Files

  • API_BEHAVIOR.md - API behavior specification
  • openapi.yaml - OpenAPI specification

Verification

Run the following commands to verify the implementation:

# Type check
npx tsc --noEmit

# Run tests
npm test

# Check specific test files
npm test -- tests/helpers.test.ts
npm test -- tests/routes/streams.test.ts
npm test -- tests/routes/health.test.ts

Next Steps

  1. Update API client libraries to handle new envelope structure
  2. Update API documentation and examples
  3. Communicate breaking changes to API consumers
  4. Consider versioning strategy (e.g., /v2/api/streams)
  5. Monitor error logs for any missed edge cases

Conclusion

The standardized error envelope implementation provides a consistent, predictable API surface that improves developer experience and makes the API easier to consume. All routes now follow the same response structure, with comprehensive test coverage and updated documentation.