@manrp/http-problem
v1.0.2
Published
Typed HTTP & domain error abstraction with RFC7807 support, multi-runtime compatibility, and adapters for Fetch and GraphQL
Maintainers
Readme
@manrp/http-problem
Typed HTTP & domain error abstraction with RFC7807 support, multi-runtime compatibility, and adapters for Fetch and GraphQL.
Inspired by hapi/boom, but designed for modern TypeScript with strong typing, extensibility, and zero runtime dependencies.
✨ Features
- 🔒 Fully typed HTTP errors
- 🧠 Domain → HTTP error mapping
- 📦 RFC 7807 (Problem Details) compliant output
- 🌐 Works in Node.js, Bun, Deno, and browser
- 🔌 Built-in adapters for Fetch API and GraphQL
- 🧩 Extensible domain errors via
withDomain - ✨ Custom domain methods generated in
camelCase - 🚫 No dependencies
- ⚡ High DX (factory-style API, no
new)
📥 Installation
npm install @manrp/http-problem🚀 Quick Start
import { HttpProblem } from '@manrp/http-problem';
throw HttpProblem.notFound('User not found');🌐 HTTP Errors
Create HTTP errors using static factory methods:
HttpProblem.badRequest();
HttpProblem.unauthorized();
HttpProblem.forbidden();
HttpProblem.notFound();
HttpProblem.internalServerError();All errors are strongly typed:
const err = HttpProblem.notFound();
err.code; // "NOT_FOUND"
err.status; // 404
err.title; // "Not Found"🧠 Domain Errors
Map domain-level errors to HTTP automatically:
throw HttpProblem.fromDomain('VALIDATION_ERROR');Includes metadata:
const err = HttpProblem.fromDomain('VALIDATION_ERROR');
err.meta?.domainCode; // "VALIDATION_ERROR"🧩 Custom Domain Errors
Extend the system with your own domain errors and get a specialized HttpProblem class:
const AppProblem = HttpProblem.withDomain({
USER_BLOCKED: {
http: 'FORBIDDEN',
message: 'User is blocked'
},
PAYMENT_FAILED: {
http: 'BAD_REQUEST',
message: 'Payment failed'
}
} as const);Usage:
throw AppProblem.fromDomain('USER_BLOCKED');
throw AppProblem.userBlocked();
throw AppProblem.paymentFailed('Card declined');withDomain(...) keeps the native HTTP factories, the built-in domain factories, and adds methods for each custom domain key normalized to camelCase.
Example:
AppProblem.notFound();
AppProblem.validationError();
AppProblem.userBlocked();✔ Features
- Fully typed (keys + HTTP mapping)
- Supports base + custom domain errors
- Adds custom domain methods with dot notation
- No global state
- Composable per module or context
TypeScript helpers
The package also exports helper types for advanced composition:
import type { DomainMethodsOf, WithDomainResult } from '@manrp/http-problem';
type AppProblem = WithDomainResult<typeof AppDomain>;
type AppProblemMethods = DomainMethodsOf<typeof AppDomain>;These are especially useful when you want to expose your own wrapped error module or framework abstraction while preserving the inferred domain factories.
🧱 Domain Composition
You control how domain errors are composed:
const Domain = {
...AuthDomain,
...PaymentDomain,
} as const;
const Problem = HttpProblem.withDomain(Domain);
throw Problem.invalidCredentials();
throw Problem.paymentFailed();📦 RFC 7807 (Problem Details)
Generate standardized error responses:
const err = HttpProblem.notFound('User not found');
err.toRFC7807();Output:
{
"type": "about:blank",
"title": "Not Found",
"status": 404,
"detail": "User not found",
"code": "NOT_FOUND"
}🌐 Fetch API Integration
Return a Response directly:
return HttpProblem.notFound().toResponse();Content-Type:
application/problem+json🔗 GraphQL Integration
Convert to GraphQL error format:
throw HttpProblem.notFound().toGraphQl();🧠 Unknown Errors
Normalize unknown values safely:
HttpProblem.fromUnknown(err);Force internal error:
HttpProblem.ensureInternal(err);🔁 From HTTP Status
Create error from status code:
HttpProblem.fromStatus(404);🔍 Type Guard
if (HttpProblem.isHttpProblem(err)) {
console.log(err.code);
}⚙️ Visibility Policy
Control exposed details:
err.toRFC7807({
fallbackMessage: 'Unexpected error',
visibility: {
exposeDetails: () => false,
exposeMeta: () => false
}
});🧠 Design Principles
- No global state
- Strong typing over magic
- Composition over configuration
- Runtime agnostic
- Predictable and explicit API
📄 License
MIT
