π¨ We have an application/problem+json!
- π Fully compliant. Fully compliant with the RFC 7807 specification!
- π Configurable. Supports custom JSON stringify functions!
- π Support for templating. Create template functions to generate errors from parameters!
- π Tiny. Total bundle size comes in at 3xx bytes minified + gzipped!
- π‘ Lightweight. Tiny (see above), zero dependencies, and tree-shakeable!
- π€ Integrable. Works with Next.js API routes, Cloudflare Workers, and Netlify Functions out-of-the-box!
- πͺ TypeScript. Fully typed and self-documenting!
- π Support for Node.js >=10.24!
# npm
npm i @moducate/houston
# or yarn
yarn add @moducate/houston
// ESM / TypeScript
import { withError } from "@moducate/houston";
// or CommonJS
const { withError } = require("@moducate/houston");
You can create error templates using the exported withTemplate
function:
const { withTemplate } = require("@moducate/houston");
const app = require("express")();
const [withUserNotFound, rawUserNotFound] = withTemplate(({ userId }) => ({
type: "https://example.com/user-not-found",
status: 404,
instance: `/users/${userId}`,
}));
app.get("/not-found", (_, res) => {
return withUserNotFound(res, { userId: 1 });
});
const res = rawUserNotFound({ userId: 1 });
// => The second function returned by withTemplate transforms and returns an object (decoupled from http.ServerResponse)
console.log(JSON.stringify(res));
// => { "type": "https://example.com/user-not-found", "status": 404, "instance": "/users/1" }
If you are not needing to use both functions, you can use this handy shorthand to obtain one of them:
const { withTemplate } = require("@moducate/houston");
const [withNotFound] = withTemplate(() => ({ type: "https://example.com/not-found", status: 404 }));
// => Returns the function that transforms a http.ServerResponse
const [, withNotFound] = withTemplate(() => ({ type: "https://example.com/not-found", status: 404 }));
// => Returns the raw function for transforming an object
withTemplate
supports TypeScript generics so you can have type definitions for your template's parameters:
const [withUserNotFound] = withTemplate<{ userId: number }>(({ userId }) => ({
type: "https://example.com/user-not-found",
status: 404,
instance: `/users/${userId}`,
}));
// => withUserNotFound's second parameter (`params`) now has the type `{ userId: number }`
The exported mime
constant can be used to obtain the media/MIME type for RFC 7807 JSON errors.
const { mime } = require("@moducate/houston");
console.log(mime);
// => 'application/problem+json'
This is what the Content-Type
header of the response supplied to withError
is set to.
You can supply options as an additional parameter to withError
and withTemplate
(and the subsequent withError
function
returned by the template) to configure Houston's behaviour:
...
withError(
res,
{ type: "https://example.com/not-found", status: 404 },
{ /* options */ },
);
...
You can supply a custom function used to stringify the error response's JSON body.
By default,
JSON.stringify
is used.
π Full source code for these examples can be found in the
examples
directory.
const { withError } = require("@moducate/houston");
const app = require("express")();
app.get("/not-found", (_, res) => {
return withError(res, { type: "https://example.com/not-found", status: 404 });
});
import { withError } from "@moducate/houston/nextjs";
export default function handler(req, res) {
return withError(req, res, { type: "https://example.com/not-found", status: 404 });
}
import { withError } from "@moducate/houston/cf-workers";
addEventListener("fetch", event => {
return withError(event, { type: "https://example.com/not-found", status: 404 });
});
import { withError } from "@moducate/houston/netlify";
import type { Handler } from "@netlify/functions";
const handler: Handler = async (event, context) => {
return withError(event, { type: "https://example.com/not-found", status: 404 });
};
export { handler };
β Fastify uses a custom
Reply
class, rather thanhttp.ServerResponse
.This means you need to supply
reply.raw
(instead ofreply
) towithError()
.
const { withError } = require("@moducate/houston");
const app = require("fastify")();
app.get("/not-found", (_, reply) => {
return withError(reply.raw, { type: "https://example.com/not-found", status: 404 });
});
See the examples/fast-json-stringify
directory for an example project using Houston with Fastify and fast-json-stringify.
See the examples/templates
directory for an example project using Houston's templating functionality with Express.
Houston is licensed under the MIT License
.