{"id":13469638,"url":"https://github.com/htunnicliff/next-api-middleware","last_synced_at":"2025-05-15T10:05:38.947Z","repository":{"id":38051235,"uuid":"317061261","full_name":"htunnicliff/next-api-middleware","owner":"htunnicliff","description":"Middleware for API routes using the Next.js Pages Router","archived":false,"fork":false,"pushed_at":"2025-02-28T19:59:58.000Z","size":883,"stargazers_count":274,"open_issues_count":4,"forks_count":7,"subscribers_count":4,"default_branch":"canary","last_synced_at":"2025-04-14T16:54:07.013Z","etag":null,"topics":["api-middleware","api-routes","middleware","middleware-functions","next","nextjs","nodejs","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/htunnicliff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"buy_me_a_coffee":"htunnicliff"}},"created_at":"2020-11-29T23:09:46.000Z","updated_at":"2025-03-28T18:54:48.000Z","dependencies_parsed_at":"2024-11-29T13:05:46.381Z","dependency_job_id":"a9a06df3-03e2-4fac-9d33-1e4eb8f5d6d4","html_url":"https://github.com/htunnicliff/next-api-middleware","commit_stats":{"total_commits":178,"total_committers":5,"mean_commits":35.6,"dds":0.3539325842696629,"last_synced_commit":"0ae518641e6cffd4c2a17c936347c797670005f1"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htunnicliff%2Fnext-api-middleware","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htunnicliff%2Fnext-api-middleware/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htunnicliff%2Fnext-api-middleware/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/htunnicliff%2Fnext-api-middleware/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/htunnicliff","download_url":"https://codeload.github.com/htunnicliff/next-api-middleware/tar.gz/refs/heads/canary","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254297888,"owners_count":22047600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-middleware","api-routes","middleware","middleware-functions","next","nextjs","nodejs","react"],"created_at":"2024-07-31T15:01:48.147Z","updated_at":"2025-05-15T10:05:33.855Z","avatar_url":"https://github.com/htunnicliff.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/htunnicliff"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003eNext.js API Middleware\u003c/h1\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca aria-label=\"npm\" href=\"https://www.npmjs.com/package/next-api-middleware\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/next-api-middleware.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"npm downloads\" href=\"https://www.npmjs.com/package/next-api-middleware\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/dm/next-api-middleware\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"license\" href=\"https://github.com/htunnicliff/next-api-middleware/blob/master/LICENSE\"\u003e\n    \u003cimg alt=\"license\" src=\"https://img.shields.io/github/license/htunnicliff/next-api-middleware.svg\"\u003e\n  \u003c/a\u003e\n   \u003ca aria-label=\"tests\" href=\"https://github.com/htunnicliff/next-api-middleware/actions?query=workflow%3ATest\"\u003e\n    \u003cimg alt=\"GitHub Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/htunnicliff/next-api-middleware/main.yaml?label=Tests\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"coverage\" href=\"https://codecov.io/gh/htunnicliff/next-api-middleware/\"\u003e\n    \u003cimg alt=\"Codecov\" src=\"https://img.shields.io/codecov/c/github/htunnicliff/next-api-middleware?\u0026\u0026token=XI7G8L08TY\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Introduction\n\n\u003e ⚠️ **This library was written to support API routes that use the Next.js [Pages Router](https://nextjs.org/docs/pages). It has not been tested with the [App Router](https://nextjs.org/docs/app).**\n\n[Next.js API routes](https://nextjs.org/docs/api-routes/introduction) are a ridiculously fun and simple way to add backend functionality to a React app. However, when it comes time to add middleware, there is no easy way to implement it.\n\nThe official Next.js docs recommend writing functions [inside your API route handler](https://nextjs.org/docs/api-routes/api-middlewares). This is a huge step backward compared to the clean APIs provided by Express.js or Koa.js.\n\nThis library attempts to provide minimal, clean, composable middleware patterns that are both productive and pleasant to use.\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [How It Works](#quick-start)\n- [APIs](#apis)\n  - [`label`](#label)\n  - [`use`](#use)\n- [Usage Guide](#usage-guide)\n- [Advanced](#advanced)\n  - [Middleware Factories](#middleware-factories)\n  - [Middleware Signature](#middleware-types)\n- [Alternatives](#alternatives)\n\n## Quick Start\n\n```ts\nimport { label, Middleware } from \"next-api-middleware\";\nimport * as Sentry from \"@sentry/nextjs\";\nimport nanoid from \"nanoid\";\n\n// 1 – Create middleware functions\n\nconst captureErrors: Middleware = async (req, res, next) =\u003e {\n  try {\n    // Catch any errors that are thrown in remaining\n    // middleware and the API route handler\n    await next();\n  } catch (err) {\n    const eventId = Sentry.captureException(err);\n\n    res.status(500);\n    res.json({ error: err });\n  }\n};\n\nconst addRequestId: Middleware = async (req, res, next) =\u003e {\n  // Let remaining middleware and API route execute\n  await next();\n\n  // Apply header\n  res.setHeader(\"X-Response-ID\", nanoid());\n};\n\n// 2 – Use `label` to assemble all middleware\n\nconst withMiddleware = label(\n  {\n    addRequestId,\n    sentry: captureErrors, // \u003c-- Optionally alias middleware\n  },\n  [\"sentry\"] // \u003c-- Provide a list of middleware to call automatically\n);\n\n// 3 – Define your API route handler\n\nconst apiRouteHandler = async (req, res) =\u003e {\n  res.status(200);\n  res.send(\"Hello world!\");\n};\n\n// 4 – Choose middleware to invoke for this API route\n\nexport default withMiddleware(\"addRequestId\")(apiRouteHandler);\n```\n\n## How It Works\n\nMy mental model for how this library handles middleware functions is that of a \"winding and unwinding stack.\"\n\nLet's imagine you've used `label` to add two middleware functions to an API route.\n\nWhen a request comes in, this is a rough impression of how that request makes its way through all middleware functions, the API route handler itself, and then back up through the middleware.\n\n```\n              |-----------------|-----------------|--------------------|\n              |  Middleware #1  |  Middleware #2  | API Route Handler  |\n              |-----------------|-----------------|--------------------|\n              |                 |                 |                    |\nRequest ------|----\u003e Setup -----|----\u003e Setup -----|--\u003e------|          |\n              |                 |                 |         |          |\n              |-----------------|-----------------|         V          |\n              |                 |                 |                    |\n              |   await next()  |   await next()  |     API stuff      |\n              |                 |                 |                    |\n              |-----------------|-----------------|         |          |\n              |                 |                 |         |          |\nResponse \u003c----|--- Teardown \u003c---|--- Teardown \u003c---|---------|          |\n              |                 |                 |                    |\n              |-----------------|-----------------|--------------------|\n```\n\nWhile this is a crummy ASCII diagram, I think it gives the right impression. The request winds its way though each middleware function in succession, hits the API route handler, and then proceeds to \"unwind\" its way through the stack.\n\nEvery middleware function has the opportunity to go through three phases:\n\n1. Setup\n2. Waiting\n3. Teardown\n\nThe \"Setup\" phase covers everything that happens before `await next()`. The \"Waiting\" phase is really just `await next()`. The \"Teardown\" phase is the remaining code within a middleware function after `await next()`.\n\nIt is worth noting that although these phases are available to all middleware functions, you don't need to take advantage of them all.\n\nFor example, in error catching middleware you might simply wrap `await next()` in a `try / catch` block. On the other hand, you might have request timing middleware that captures a start time during the setup phase, waits, and then captures a finish time in the teardown phase.\n\n## APIs\n\n### `label`\n\nThis is the primary utility for creating reusuable collections of middleware for use throughout many Next.js API routes.\n\n```ts\nconst withMiddleware = label(middleware, defaults);\n```\n\n#### Parameters\n\n- `middleware`: an object containing middleware functions or arrays of middleware\n- `defaults`: (optional) an array of `middleware` keys that will be invoked automatically\n\n#### Return Value\n\n`label` returns a function (conventionally referred to as `withMiddleware`) that uses currying to accept a list of middleware names to be invoked, followed by a Next.js API handler function.\n\nTypically, `withMiddleware` will be imported in API route files and used at the default export statement:\n\n```ts\nimport { withMiddleware } from \"../helpers/my-middleware\";\n\nconst apiRouteHandler = async (req, res) =\u003e {\n  ...\n}\n\nexport default withMiddleware(\"foo\", \"bar\", \"baz\")(apiRouteHandler);\n```\n\nThough `label` could contain many middleware functions, the actual middleware invoked by an API route is determined by the names passed in to `withMiddleware`.\n\n#### Examples\n\n##### Basic Use\n\n```ts\nconst logErrors = async (req, res, next) =\u003e {\n  try {\n    await next();\n  } catch (error) {\n    console.error(error);\n    res.status(500);\n    res.json({ error });\n  }\n};\n\nconst withMiddleware = label({\n  logErrors,\n});\n\n// export default withMiddleware(\"logErrors\")(apiRouteHandler);\n```\n\n##### Aliases\n\n```ts\nconst withMiddleware = label({\n  error: logErrors,\n});\n\n// export default withMiddleware(\"error\")(apiRouteHandler);\n```\n\n##### Groups\n\n```ts\nimport { foo, bar, baz } from \"./my-middleware\";\n\nconst withMiddleware = label({\n  error: logErrors,\n  myGroup: [foo, bar, baz],\n});\n\n// export default withMiddleware(\"error\", \"myGroup\")(apiRouteHandler);\n```\n\n##### Defaults\n\n```ts\nconst withMiddleware = label(\n  {\n    error: logErrors,\n    myGroup: [foo, bar, baz],\n  },\n  [\"error\"]\n);\n\n// export default withMiddleware(\"myGroup\")(apiRouteHandler);\n```\n\n### `use`\n\nThis utility accepts middleware functions directly and executes them all in order. It is a simpler alternative to `label` that can be useful for handling one-off middleware functions.\n\n```ts\nconst withInlineMiddleware = use(...middleware);\n```\n\n#### Parameters\n\n- `middleware`: a list of middleware functions and/or arrays of middleware functions\n\n#### Return Value\n\n`use` returns a function that accepts a Next.js API route handler.\n\n#### Examples\n\n##### CORS\n\n```ts\nimport { use } from \"next-api-middleware\";\nimport cors from \"cors\";\n\nconst apiRouteThatOnlyNeedsCORS = async (req, res) =\u003e {\n  ...\n}\n\nexport default use(cors())(apiRouteThatOnlyNeedsCORS);\n```\n\n## Usage Guide\n\nSee [EXAMPLES.md](./EXAMPLES.md) for more detailed examples of `label` and `use`.\n\n## Advanced\n\n### Middleware Factories\n\nSince `use` and `label` accept values that evaluate to middleware functions, this provides the opportunity to create custom middleware factories.\n\nHere's an example of a factory that generates a middleware function to only allow requests with a given HTTP method:\n\n```ts\nimport { Middleware } from \"next-api-middleware\";\n\nconst httpMethod = (\n  allowedHttpMethod: \"GET\" | \"POST\" | \"PATCH\"\n): Middleware =\u003e {\n  return async function (req, res, next) {\n    if (req.method === allowedHttpMethod || req.method == \"OPTIONS\") {\n      await next();\n    } else {\n      res.status(404);\n      res.end();\n    }\n  };\n};\n\nexport const postRequestsOnlyMiddleware = httpMethod(\"POST\");\n```\n\n### Middleware Signature\n\n`Middleware` is inspired by the asyncronous middleware style popularized by Koa.js.\n\n```ts\ntype Middleware\u003cRequest = NextApiRequest, Response = NextApiResponse\u003e = (\n  req: Request,\n  res: Response,\n  next: () =\u003e Promise\u003cvoid\u003e\n) =\u003e Promise\u003cvoid\u003e;\n```\n\n## Alternatives\n\n- [next-connect](https://github.com/hoangvvo/next-connect)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtunnicliff%2Fnext-api-middleware","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhtunnicliff%2Fnext-api-middleware","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhtunnicliff%2Fnext-api-middleware/lists"}