@tlsft/service-error
v0.1.0
Published
The service error: what a service call fails with, an Error with an HTTP-style status, a code and details that survives crossing any boundary
Maintainers
Readme
@tlsft/service-error
One error for every service call, wherever it runs:
throw notFound('No such message')
// ServiceError {status: 404, code: 'NOT_FOUND', message: 'No such message'}Why a service error
A service call may be answered in-process, over a message bus, by a replica, or over HTTP. Its caller should not need to know which to tell "not found" from "forbidden". A service error carries that meaning in fields a program can read: an HTTP-style status, a string code, a message, and optional details.
- HTTP's vocabulary, not HTTP's transport. Status codes are the error language most callers already speak, so an HTTP adapter maps an error to a response with no table of its own, and nothing else has to be HTTP.
- Survives boundaries. An error crosses a native core, a log or a network as plain data, and comes back as the same error: status, code, message and details intact.
- Small. No dependencies.
Use
import {notFound, forbidden, serializeError, deserializeError, toServiceError} from '@tlsft/service-error'
// Originate one in a handler.
throw forbidden('Only the author may edit a message', {author})
// Send one across a boundary, and get the same error back on the other side.
const data = serializeError(error) // {status: 403, code: 'FORBIDDEN', message, details}
const same = deserializeError(data) // ServiceError
// Settle anything caught into a ServiceError.
toServiceError(new TypeError('x')) // 500 INTERNAL_ERROR, message 'TypeError: x', stack kept| Template | Status | Code |
| --- | --- | --- |
| badRequest | 400 | BAD_REQUEST |
| unauthorized | 401 | UNAUTHORIZED |
| forbidden | 403 | FORBIDDEN |
| notFound | 404 | NOT_FOUND |
| methodNotAllowed | 405 | METHOD_NOT_ALLOWED |
| conflict | 409 | CONFLICT |
| validationError | 422 | VALIDATION_ERROR |
| internalError | 500 | INTERNAL_ERROR |
| serviceUnavailable | 503 | SERVICE_UNAVAILABLE |
| gatewayTimeout | 504 | GATEWAY_TIMEOUT |
Any other status or code is new ServiceError(status, code, message, details).
isServiceError is duck-typed: any value with a numeric status and a string code counts, so errors from libraries with the same shape, such as MicroQL's catalogued errors, keep their meaning instead of collapsing into a 500. Serialized data leaves the stack behind. Whether to hide an unexpected error's message from a remote caller is the adapter's choice.
Related
MicroQL raises errors of this shape. @tlsft/service-key names the calls they come from.
