Package Exports
- @xavierdev25/rfc7807-errors
- @xavierdev25/rfc7807-errors/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@xavierdev25/rfc7807-errors) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@xavierdev25/rfc7807-errors
Global NestJS exception engine implementing RFC 7807 Problem Details (
application/problem+json) — generic, validation, and database errors, automatically.
Turns every error your API throws — your own domain errors, NestJS HttpExceptions, and unexpected crashes — into a single, standard, machine-readable error shape:
{
"type": "https://api.example.com/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Transaction with ID '…' was not found.",
"instance": "/transactions/123",
"transactionId": "123"
}Built with SOLID in mind: an abstract ProblemDetailException, eight concrete LSP-correct subclasses, a framework-agnostic filter (Express/Fastify via HttpAdapterHost), and a pluggable serializer (DIP).
Install
pnpm add @xavierdev25/rfc7807-errors
# peer deps: @nestjs/common, @nestjs/core, rxjsQuick start
import { Module } from '@nestjs/common';
import { Rfc7807Module } from '@xavierdev25/rfc7807-errors';
@Module({
imports: [
Rfc7807Module.forRoot({
// Type URIs become `${typeBaseUri}/${error-slug}` (default: 'about:blank')
typeBaseUri: 'https://api.example.com/errors',
// Stack traces are added only when NODE_ENV !== 'production'
includeStackTrace: process.env.NODE_ENV !== 'production',
// Hook for logging / metrics / error tracking
onProblem: (problem, exception) => logger.error(problem.title, exception),
}),
],
})
export class AppModule {}forRoot registers the Rfc7807ExceptionFilter globally (APP_FILTER). No manual useGlobalFilters needed.
Throwing problems
Eight ready-made exceptions, one per common HTTP status:
| Class | Status |
|---|---|
BadRequestProblem |
400 |
UnauthorizedProblem |
401 |
ForbiddenProblem |
403 |
NotFoundProblem |
404 |
ConflictProblem |
409 |
UnprocessableEntityProblem |
422 |
TooManyRequestsProblem |
429 |
InternalServerErrorProblem |
500 |
import { ConflictProblem } from '@xavierdev25/rfc7807-errors';
throw new ConflictProblem({
detail: 'A transaction with this idempotency key already exists.',
instance: request.url, // optional; the filter fills it from the request URL
extensions: { idempotencyKey }, // any extra members are merged into the body
});Custom domain errors
Subclass a problem so your domain layer throws meaningful, typed errors that still serialize to RFC 7807:
import { NotFoundProblem } from '@xavierdev25/rfc7807-errors';
export class TransactionNotFoundError extends NotFoundProblem {
constructor(id: string) {
super({
type: 'https://api.example.com/errors/transaction-not-found',
detail: `Transaction with ID '${id}' was not found.`,
extensions: { transactionId: id },
});
}
}Async configuration
Rfc7807Module.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
typeBaseUri: config.get('ERRORS_BASE_URI'),
includeStackTrace: config.get('NODE_ENV') !== 'production',
}),
});useClass and useExisting (via Rfc7807OptionsFactory) are also supported.
Automatic database error mapping
Database driver errors are translated to a meaningful HTTP status out of the
box — no try/catch in your controllers. It's dependency-free (detection is
by error shape/code), so it works whether you use TypeORM, Prisma, or the
raw pg driver. Sensitive driver detail (constraint/column/message) is
masked in production and only attached (under a dbError member) outside it.
| Source | Code | → Problem |
|---|---|---|
| PostgreSQL | 23505 unique_violation |
409 Conflict |
| PostgreSQL | 23503 foreign_key_violation |
409 Conflict |
| PostgreSQL | 23502 not_null_violation |
422 Unprocessable Entity |
| PostgreSQL | 22P02 invalid_text_representation |
400 Bad Request |
| Prisma | P2002 unique |
409 · P2025 not found → 404 · P2003 FK → 409 |
Enabled by default; disable with databaseErrors: false.
Validation errors (class-validator)
Drop the provided exceptionFactory into NestJS's ValidationPipe and every
class-validator failure becomes a 400 BadRequestProblem with a structured
violations array (field, constraints, value — nested DTOs flattened to a
dot-path):
import { ValidationPipe } from '@nestjs/common';
import { rfc7807ValidationExceptionFactory } from '@xavierdev25/rfc7807-errors';
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
exceptionFactory: rfc7807ValidationExceptionFactory,
}),
);Custom mappers (extend to any error source)
Need to map errors from gRPC, a third-party SDK, or another ORM? Implement
ExceptionMapper and register it — it runs before the built-ins, so you can
also override them (Open/Closed, no fork required):
import { ExceptionMapper } from '@xavierdev25/rfc7807-errors';
const stripeMapper: ExceptionMapper = {
map: (e) =>
e?.constructor?.name === 'StripeCardError'
? { type: 'about:blank', title: 'Payment Required', status: 402 }
: null, // null → defer to the next mapper
};
Rfc7807Module.forRoot({ mappers: [stripeMapper] });What the filter handles (in order)
- Custom
mappers(yours) → run first; can override any built-in. ProblemDetailException(yours) → serialized as-is viatoProblemDetail().- NestJS
HttpException→ mapped to RFC 7807 (validation arrays become anerrorsmember). - Database driver errors (TypeORM/Prisma/PostgreSQL) → proper status (409/422/…).
- Anything else →
500, with the detail masked in production to avoid leaking internals.
Options
| Option | Type | Default | Description |
|---|---|---|---|
typeBaseUri |
string |
'about:blank' |
Prefix for the type URI ({base}/{slug}). |
databaseErrors |
boolean |
true |
Map DB driver errors (TypeORM/Prisma/PG) to HTTP statuses. |
mappers |
ExceptionMapper[] |
[] |
Custom mappers, tried before the built-ins. |
includeStackTrace |
boolean |
false |
Add stackTrace to the body (never in production). |
onProblem |
(problem, exception) => void |
– | Side-effect hook (logging/metrics/error tracking, e.g. Sentry). |
serializer |
IProblemDetailSerializer |
JsonProblemDetailSerializer |
Custom output serializer (DIP). |
Content type: application/problem+json. See RFC 7807.