Typescript implementation of rfc 7807 problem details
Typescript implementation of RFC 7870 inspired from Hellang ProblemDetails
Problem details options
- typePrefix - Reference
- contentTypes - response content type, defaults to "application/problem+json"
- mapStatusCode - a function that creates default problem details in case there's no mapping for the current error or the
predicate
mapping didn't pass - appendCacheHeaders - a function the add no cache response header
- includeExceptionDetails - a function that determines whether to include exception details or not.
- exceptionDetailsPropertyName - the property name that will have the error stack trace, defaults to
exceptionDetails
Cache headers
By default these headers will be added
"cache-control": "no-cache, no-store, must-revalidate"
"pragma": "no-cache"
"etag": "0"
"expires": "0"
You can modify this behaviour by changing appendCacheHeaders option
// Default function
options.appendCacheHeaders = (setHeader) => {
setHeader("cache-control", "no-cache, no-store, must-revalidate");
setHeader("pragma", "no-cache");
setHeader("etag", "0");
setHeader("expires", "0");
};
// Do not add any cache header
options.appendCacheHeaders = (setHeader) => {};
// Add custom cache headers
options.appendCacheHeaders = (setHeader) => {
setHeader("cache-control", "no-cache, no-store, must-revalidate");
setHeader("pragma", "no-cache");
setHeader("etag", "0");
setHeader("expires", "0");
setHeader("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT"); // This line
};
Framework support
The library support Koa.js and express.js out of the box
- Express
import express from "express";
import { problemDetailsMiddleware } from "rfc-7807-problem-details";
const app = express();
// Should be added at the last of the middleware chain
app.use(problemDetailsMiddleware.express());
- Koa
import Koa from "koa";
import { problemDetailsMiddleware } from "rfc-7807-problem-details";
const app = new Koa();
// Should be added at the start of the middleware chain
app.use(problemDetailsMiddleware.koa());
- Deno - Oak
import { Application } from "https://deno.land/x/oak/mod.ts";
import {
ProblemDetailsException,
ProblemDetailsOptions,
ProblemDetailsSetup,
} from "https://esm.sh/rfc-7807-problem-details";
const app = new Application();
app.use(async (ctx, next) => {
// set your options before constructing ProblemDetailsSetup
const options = new ProblemDetailsOptions();
options.typePrefix = `https://example.com/probs/out-of-credit`;
const setup = new ProblemDetailsSetup(options);
return async (context: any, next: any) => {
try {
await next();
} catch (error) {
options.appendCacheHeaders((name, value) =>
ctx.response.headers.set(name, value)
);
const problem = setup.prepareProblemDetails(error, context);
ctx.response.headers.set("content-type", options.contentTypes);
context.status = problem.status;
context.body = problem;
}
};
});
app.use(async (ctx, next) => {
switch (ctx.request.url.pathname) {
case "/example/throw":
throw new ProblemDetailsException({
type: "cannot-proceed",
status: 400,
title: "You cannot proceed.",
});
default:
ctx.response.body = "Hello World";
break;
}
await next();
});
await app.listen({ port: 8000 });
If you'd like to support custom framework take a look at the source code to see how you can do it.
For more examples check the demo directory.