Skip to main content

api-errors

@rtorcato/api-errors provides typed HTTP error classes that pair with the Express and Hono error-handler middleware.

Install

pnpm add @rtorcato/api-errors

Error classes

ClassStatusDefault code
BadRequestError400bad_request
UnauthorizedError401unauthorized
ForbiddenError403forbidden
NotFoundError404not_found
ConflictError409conflict
UnprocessableEntityError422unprocessable_entity
TooManyRequestsError429too_many_requests
InternalServerError500internal_server_error
ServiceUnavailableError503service_unavailable

All extend HttpError, which extends Error.

Usage

import { NotFoundError, ForbiddenError } from '@rtorcato/api-errors'

// Default message and code
throw new NotFoundError()
// → { status: 404, code: 'not_found', message: 'Not Found' }

// Custom message
throw new NotFoundError('User 42 not found')
// → { status: 404, code: 'not_found', message: 'User 42 not found' }

// Custom message + code
throw new ForbiddenError('Trial expired', 'trial_expired')
// → { status: 403, code: 'trial_expired', message: 'Trial expired' }

Wire up the error handler

Throw from anywhere in your route — the error handler converts it to JSON automatically.

Express (@rtorcato/api-errors-express):

import { errorHandler, notFoundHandler } from '@rtorcato/api-errors-express'

app.use(notFoundHandler) // catch unmatched routes
app.use(errorHandler()) // convert HttpErrors to JSON

Hono (@rtorcato/api-errors-hono):

import { errorHandler, notFoundHandler } from '@rtorcato/api-errors-hono'

app.notFound(notFoundHandler)
app.onError(errorHandler())

Error response shape

{
"error": "NotFoundError",
"code": "not_found",
"message": "User 42 not found"
}

error is the class name. code is machine-readable and stable — safe to switch on in clients.

Custom errors

Extend HttpError for domain-specific errors:

import { HttpError } from '@rtorcato/api-errors'

export class PaymentRequiredError extends HttpError {
constructor(message = 'Payment required') {
super(402, message, 'payment_required')
this.name = 'PaymentRequiredError'
}
}

Throw it like any other — the error handler picks it up automatically because it's still an HttpError.

See Custom errors for a fuller guide.