Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/juanjh1/asimilation/llms.txt

Use this file to discover all available pages before exploring further.

Robust error handling is essential for building reliable APIs. Asimilation provides built-in error handling mechanisms and allows you to customize error responses.

Built-in Error Handling

Asimilation automatically handles common HTTP errors:

404 Not Found

When no route matches the requested URL, Asimilation automatically returns a 404 response:
GET /non-existent-route HTTP/1.1
Response:
{
  "error": "Route don't exist"
}
The 404 handler is built into the route manager (see src/core/router-manager.ts:82-90).

Method Not Allowed

When a route exists but doesn’t support the requested HTTP method:
import { url } from '@asimilation/core';

// Only accepts GET
url.addPath('/users', handler, { methods: ['GET'] });
Request:
POST /users HTTP/1.1
Response:
{
  "error": "Route don't exist"
}

Content Negotiation

Asimilation respects the Accept header for error responses:
GET /not-found HTTP/1.1
Accept: application/json

{
  "error": "Route don't exist"
}
Content negotiation is handled by the error response handler (see src/helpers/error-response.ts:5-42).

Quality Values (q-factor)

The error handler respects quality values in the Accept header:
GET /not-found HTTP/1.1
Accept: text/plain;q=0.5, application/json;q=1.0
This will return JSON because it has a higher quality value (1.0 > 0.5).

Error Response Helpers

Use response helpers to send error responses from your handlers:
url.addPath('/users/<int:id>', (req, res) => {
  const id = parseInt(req.params.id, 10);
  
  if (id < 1) {
    res.sendJson({ error: 'Invalid user ID' }, 400);
    return;
  }
  
  res.sendJson({ userId: id }, 200);
});

Common HTTP Status Codes

Use appropriate status codes for different error scenarios:
CodeMeaningWhen to Use
400Bad RequestInvalid input, malformed request
401UnauthorizedAuthentication required
403ForbiddenAuthenticated but not authorized
404Not FoundResource doesn’t exist
409ConflictDuplicate resource, state conflict
422Unprocessable EntityValidation failed
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
503Service UnavailableServer overloaded or down

Validation Errors

Handle input validation errors with appropriate messages:
import { url } from '@asimilation/core';

url.addPath('/users', (req, res) => {
  const body = (req as any).body;
  
  // Validate required fields
  if (!body.email) {
    res.sendJson({
      error: 'Validation failed',
      details: [{ field: 'email', message: 'Email is required' }]
    }, 400);
    return;
  }
  
  // Validate email format
  if (!isValidEmail(body.email)) {
    res.sendJson({
      error: 'Validation failed',
      details: [{ field: 'email', message: 'Invalid email format' }]
    }, 400);
    return;
  }
  
  res.sendJson({ message: 'User created' }, 201);
}, {
  methods: ['POST']
});

Error Handling Middleware

Create middleware to catch and handle errors globally:
import { MiddlewarePipeline } from '@asimilation/core';

MiddlewarePipeline.addMiddleware((req, res, next) => {
  try {
    next();
  } catch (error) {
    console.error('Unhandled error:', error);
    
    // Send error response
    if (!res.writableEnded) {
      res.sendJson({
        error: 'Internal Server Error',
        message: error.message
      }, 500);
    }
  }
});
Asimilation includes a default error-handling middleware (see src/default/middleware/error-handling.ts:5-18).

Handling Async Errors

Wrap async route handlers with try-catch:
import { url } from '@asimilation/core';

url.addPath('/users/<int:id>', async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    const user = await fetchUserFromDatabase(id);
    
    if (!user) {
      res.sendJson({ error: 'User not found' }, 404);
      return;
    }
    
    res.sendJson({ user }, 200);
  } catch (error) {
    console.error('Database error:', error);
    res.sendJson({ error: 'Internal server error' }, 500);
  }
});

Custom Error Types

Define custom error classes for different error scenarios:
class ValidationError extends Error {
  statusCode = 400;
  
  constructor(message: string, public details?: any) {
    super(message);
    this.name = 'ValidationError';
  }
}

class NotFoundError extends Error {
  statusCode = 404;
  
  constructor(message: string) {
    super(message);
    this.name = 'NotFoundError';
  }
}

class UnauthorizedError extends Error {
  statusCode = 401;
  
  constructor(message: string) {
    super(message);
    this.name = 'UnauthorizedError';
  }
}

Using Custom Errors

Throw custom errors and handle them in middleware:
import { url, MiddlewarePipeline } from '@asimilation/core';

// Error handling middleware
MiddlewarePipeline.addMiddleware((req, res, next) => {
  try {
    next();
  } catch (error: any) {
    console.error(error);
    
    if (!res.writableEnded) {
      const statusCode = error.statusCode || 500;
      const message = error.message || 'Internal Server Error';
      
      res.sendJson({
        error: error.name || 'Error',
        message,
        ...(error.details && { details: error.details })
      }, statusCode);
    }
  }
});

// Route that throws custom errors
url.addPath('/users/<int:id>', async (req, res) => {
  const id = parseInt(req.params.id, 10);
  
  if (id < 1) {
    throw new ValidationError('Invalid user ID', {
      field: 'id',
      value: id
    });
  }
  
  const user = await fetchUser(id);
  if (!user) {
    throw new NotFoundError(`User ${id} not found`);
  }
  
  res.sendJson({ user }, 200);
});

Built-in Exception Types

Asimilation includes several exception types:
import { RouteNotFoundError } from 'asimilation/exceptions';

// Thrown when a handler is not found
throw new RouteNotFoundError();
// Message: "handler not found"
Exception types are defined in src/exceptions/ directory.

Handling 404s for Specific Paths

Create a catch-all route to handle 404s with custom logic:
import { url } from '@asimilation/core';

// All your normal routes
url.addPath('/users', usersHandler);
url.addPath('/posts', postsHandler);

// Custom 404 handler (this won't actually catch 404s in Asimilation)
// The framework handles 404s automatically
Asimilation’s built-in 404 handling cannot be easily overridden. The framework automatically returns a 404 response when no route matches.

Checking Response State

Always check if the response has been sent before writing:
url.addPath('/data', (req, res) => {
  // Some middleware might have already sent a response
  if (res.writableEnded) {
    return; // Response already sent, don't write again
  }
  
  res.sendJson({ data: 'value' }, 200);
});
The router checks res.writableEnded before calling handlers (see src/core/router-manager.ts:138).

Error Response Format

Establish a consistent error response format:
interface ErrorResponse {
  error: string;           // Error type or category
  message: string;         // Human-readable message
  details?: any;           // Additional error details
  timestamp?: string;      // When the error occurred
  path?: string;          // Request path
  requestId?: string;     // Request ID for tracking
}

// Example usage
function sendError(
  res: ArgumentedServerResponseAbc,
  error: string,
  message: string,
  statusCode: number,
  details?: any
) {
  const response: ErrorResponse = {
    error,
    message,
    timestamp: new Date().toISOString(),
    ...(details && { details })
  };
  
  res.sendJson(response, statusCode);
}

// In your route
url.addPath('/users', (req, res) => {
  const body = (req as any).body;
  
  if (!body.email) {
    sendError(res, 'ValidationError', 'Email is required', 400, {
      field: 'email'
    });
    return;
  }
  
  res.sendJson({ message: 'User created' }, 201);
});

Logging Errors

Log errors for debugging and monitoring:
import { MiddlewarePipeline } from '@asimilation/core';

MiddlewarePipeline.addMiddleware((req, res, next) => {
  try {
    next();
  } catch (error: any) {
    // Log error with context
    console.error({
      timestamp: new Date().toISOString(),
      method: req.method,
      url: req.url,
      error: error.message,
      stack: error.stack,
      requestId: (req as any).requestId
    });
    
    // Send error response
    if (!res.writableEnded) {
      res.sendJson({
        error: 'Internal Server Error',
        requestId: (req as any).requestId
      }, 500);
    }
  }
});

Best Practices

1

Use appropriate status codes

Choose the HTTP status code that best matches the error:
// Bad: Using 500 for validation errors
res.sendJson({ error: 'Invalid email' }, 500);

// Good: Using 400 for validation errors
res.sendJson({ error: 'Invalid email' }, 400);
2

Provide helpful error messages

Give users enough information to fix the problem:
// Less helpful
res.sendJson({ error: 'Invalid input' }, 400);

// More helpful
res.sendJson({
  error: 'Validation failed',
  details: [{ field: 'email', message: 'Email format is invalid' }]
}, 400);
3

Don't leak sensitive information

Never expose internal errors or stack traces in production:
// Bad: Exposing internal errors
res.sendJson({ error: error.stack }, 500);

// Good: Generic error message
res.sendJson({ error: 'Internal server error' }, 500);
console.error(error); // Log internally
4

Handle async errors

Always wrap async code in try-catch:
url.addPath('/data', async (req, res) => {
  try {
    const data = await fetchData();
    res.sendJson({ data }, 200);
  } catch (error) {
    res.sendJson({ error: 'Failed to fetch data' }, 500);
  }
});
5

Check response state

Don’t write to responses that have already ended:
if (res.writableEnded) {
  return;
}
res.sendJson({ data: 'value' }, 200);

What’s Next?

Middleware Pipeline

Learn how to use middleware for error handling

API Reference

Explore the request and response API

Build docs developers (and LLMs) love