diff --git a/README.md b/README.md index 928bc3a..0d9f6b2 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,55 @@ const { GET } = compose({ export { GET }; ``` +## Error handling + +Handling errors both in middleware and in the main handler is as simple as providing `sharedErrorHandler` to the `compose` function's second parameter _(a.k.a compose settings)_. Main goal of the shared error handler is to provide clear and easy way to e.g. send the error metadata to Sentry or other error tracking service. + +By default, shared error handler looks like this: + +```ts +sharedErrorHandler: { + handler: undefined; + // ^^^^ This is the handler function. By default there is no handler, so the error is being just thrown. + includeRouteHandler: false; + // ^^^^^^^^^^^^^^^^ This toggles whether the route handler itself should be included in a error handled area. + // By default only middlewares are being caught by the sharedErrorHandler +} +``` + +... and some usage example: + +```ts +// [...] +function errorMiddleware() { + throw new Error("foo"); +} + +const { GET } = compose( + { + GET: [ + [errorMiddleware], + () => { + // Unreachable code due to errorMiddleware throwing an error and halting the chain + return new Response(JSON.stringify({ foo: "bar" })); + }, + ], + }, + { + sharedErrorHandler: { + handler: (_method, error) => { + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); + }, + }, + } +); +// [...] +``` + +will return `{"error": "foo"}` along with `500` status code instead of throwing an error. + ## Theory and caveats 1. Unfortunately there is no way to dynamically export named ESModules _(or at least I did not find a way)_ so you have to use `export { GET, POST }` syntax instead of something like `export compose(...)` if you're composing GET and POST methods :( @@ -113,4 +162,4 @@ The project is licensed under The MIT License. Thanks for all the contributions! [next-api-route-handlers]: https://nextjs.org/docs/app/building-your-application/routing/route-handlers [next-app-router-intro]: https://nextjs.org/docs/app/building-your-application/routing#the-app-router [next-app-router]: https://nextjs.org/docs/app -[next-pages-router]: https://nextjs.org/docs/pages \ No newline at end of file +[next-pages-router]: https://nextjs.org/docs/pages diff --git a/packages/next-api-compose/src/app.ts b/packages/next-api-compose/src/app.ts index 28aab88..b4ec619 100644 --- a/packages/next-api-compose/src/app.ts +++ b/packages/next-api-compose/src/app.ts @@ -18,7 +18,16 @@ type NextApiMethodHandler = ( type ComposeSettings = PartialDeep<{ sharedErrorHandler: { + /** + * @param {NextApiRouteMethod} method HTTP method of the composed route handler that failed. + * @param {Error} error Error that was thrown by the middleware or the handler. + */ handler: (method: NextApiRouteMethod, error: Error) => Promisable + /** + * Whether to include the route handler in the error handled area. + * + * By default only middlewares are included (being caught by the sharedErrorHandler). + */ includeRouteHandler: boolean } }> @@ -46,6 +55,7 @@ type ComposeParameters< * Function that allows to define complex API structure in Next.js App router's Route Handlers. * * @param {ComposeParameters} parameters Middlewares array **(order matters)** or options object with previously mentioned middlewares array as `middlewareChain` property and error handler shared by every middleware in the array as `sharedErrorHandler` property. + * @param {ComposeSettings} composeSettings Settings object that allows to configure the compose function. * @returns Method handlers with applied middleware. */ export function compose<