next-api-middleware
Advanced tools
Comparing version 0.7.0-canary.1 to 0.7.0
{ | ||
"name": "next-api-middleware", | ||
"version": "0.7.0-canary.1", | ||
"version": "0.7.0", | ||
"description": "Middleware solution for Next.js API routes", | ||
@@ -5,0 +5,0 @@ "repository": "git@github.com:htunnicliff/next-api-middleware.git", |
138
README.md
@@ -30,4 +30,7 @@ # Next.js API Middleware | ||
import { use } from "next-api-middleware"; | ||
import cors from "cors"; | ||
const middleware = use( | ||
// Create a wrapper function that executes middleware | ||
// before and after an API route request | ||
const withMiddleware = use( | ||
async (req, res, next) => { | ||
@@ -38,3 +41,2 @@ console.log("Do work before the request"); | ||
}, | ||
async (req, res, next) => { | ||
@@ -45,4 +47,4 @@ console.log("Do more work"); | ||
}, | ||
(req, res, next) => { | ||
cors(), // <---- Invoke Express/Connect middleware like any other middleware | ||
async (req, res, next) => { | ||
console.log("Store user in request"); | ||
@@ -56,6 +58,7 @@ req.locals = { | ||
return next(); | ||
await next(); | ||
} | ||
); | ||
// Create a normal Next.js API route handler | ||
const apiRouteHandler = async (req, res) => { | ||
@@ -68,3 +71,4 @@ const { name } = req.locals.user; | ||
export default middleware(apiRouteHandler); | ||
// Export the route handler wrapped inside the middleware function | ||
export default withMiddleware(apiRouteHandler); | ||
@@ -76,2 +80,3 @@ /** | ||
* Do more work | ||
* cors | ||
* Store user in request | ||
@@ -85,20 +90,34 @@ * Clean up more | ||
### :one: Create Middleware Functions | ||
### Writing Async Middleware | ||
```ts | ||
import type { Middleware } from "next-api-middleware"; | ||
import type { NextMiddleware } from "next-api-middleware"; | ||
export const addRequestUUID: Middleware = (req, res, next) => { | ||
// Middleware that does work before a request | ||
export const addRequestUUID: NextMiddleware = async (req, res, next) => { | ||
// Set a custom header | ||
res.setHeader("X-Response-ID", uuid()); | ||
return next(); | ||
// Execute the remaining middleware | ||
await next(); | ||
}; | ||
export const addRequestTiming: Middleware = async (req, res, next) => { | ||
// Middleware that does work before *and* after a request | ||
export const addRequestTiming: NextMiddleware = async (req, res, next) => { | ||
// Set a custom header before other middleware and the route handler | ||
res.setHeader("X-Timing-Start", new Date().getTime()); | ||
// Execute the remaining middleware | ||
await next(); | ||
// Set a custom header | ||
res.setHeader("X-Timing-End", new Date().getTime()); | ||
}; | ||
export const logErrorsWithACME: Middleware = async (req, res, next) => { | ||
// Middleware that catches errors that occur in remaining middleware | ||
// and the request | ||
export const logErrorsWithACME: NextMiddleware = async (req, res, next) => { | ||
try { | ||
// Catch any errors that are thrown in remaining | ||
// middleware and the API route handler | ||
await next(); | ||
@@ -113,3 +132,3 @@ } catch (error) { | ||
### :two: Compose Reusable Groups | ||
### Composing Middleware Groups | ||
@@ -125,3 +144,5 @@ ```js | ||
export const authMiddleware = use( | ||
// Create a middleware wrapper to be used on API routes | ||
// that need authentication | ||
export const withAuthMiddleware = use( | ||
addRequestTiming, | ||
@@ -134,3 +155,5 @@ logErrorsWithACME, | ||
export const guestMiddleware = use( | ||
// Create a middleware wrapper to be used on API routes | ||
// that are only used by guests | ||
export const withGuestMiddleware = use( | ||
isProduction ? [addRequestTiming, logErrorsWithACME] : [], | ||
@@ -140,3 +163,6 @@ addRequestUUID | ||
export const otherMiddleware = use( | ||
// Create a middleware wrapper using arrays of middleware | ||
// functions; these are flattened and executed in the order | ||
// in which they are provided | ||
export const withXYZMiddleware = use( | ||
[addRequestUUID, connectDatabase, loadUsers], | ||
@@ -159,8 +185,10 @@ [addRequestTiming, logErrorsWithACME] | ||
const middleware = label( | ||
// Create a middleware wrapper that imports middleware and | ||
// assigns friendly labels | ||
const withMiddleware = label({ | ||
timing: addRequestTiming, | ||
logErrors: logErrorsWithACME, | ||
uuids: addRequestUUID, | ||
all: [addRequestTiming, logErrorsWithACME, addRequestUUID] | ||
); | ||
all: [addRequestTiming, logErrorsWithACME, addRequestUUID], | ||
}); | ||
@@ -174,4 +202,5 @@ const apiRouteHandler = async (req, res) => { | ||
// Invokes `addRequestTiming` and `logErrorsWithACME` | ||
export default middleware(["timing", "logErrors"])(apiRouteHandler); | ||
// Only invoke `addRequestTiming` and `logErrorsWithACME`, using their | ||
// friendly labels | ||
export default withMiddleware("timing", "logErrors")(apiRouteHandler); | ||
``` | ||
@@ -181,17 +210,2 @@ | ||
### :three: Apply Middleware to API Routes | ||
To apply a middleware group to an API route, just import it and provide the API route handler as an argument: | ||
```js | ||
import { withGuestMiddleware } from "../../middleware/groups"; | ||
const apiHandler = async (req, res) => { | ||
res.status(200); | ||
res.send("Hello, world!"); | ||
}; | ||
export default withGuestMiddleware(apiHandler); | ||
``` | ||
## Advanced | ||
@@ -206,7 +220,7 @@ | ||
```ts | ||
import { use, Middleware } from "next-api-middleware"; | ||
import { use, NextMiddleware } from "next-api-middleware"; | ||
const httpMethod = ( | ||
allowedHttpMethod: "GET" | "POST" | "PATCH" | ||
): Middleware => { | ||
): NextMiddleware => { | ||
return async function (req, res, next) { | ||
@@ -229,1 +243,49 @@ if (req.method === allowedHttpMethod || req.method == "OPTIONS") { | ||
``` | ||
### Middleware Types | ||
`next-api-middleware` supports two middleware signatures, `NextMiddleware` and `ExpressMiddleware`. | ||
#### `NextMiddleware` (preferred) | ||
`NextMiddleware` is inspired by the asyncronous middleware style popularized by Koa.js. Prefer this style when writing your own middleware. | ||
```ts | ||
interface NextMiddleware { | ||
( | ||
req: NextApiRequest, | ||
res: NextApiResponse, | ||
next: () => Promise<void> | ||
): Promise<void>; | ||
} | ||
``` | ||
#### `ExpressMiddleware` | ||
`ExpressMiddleware` roughly matches the signature used by Express/Connect style middleware. This type can be used when importing third-party libraries such as `cors`. | ||
```ts | ||
interface ExpressMiddleware< | ||
Request = IncomingMessage, | ||
Response = ServerResponse | ||
> { | ||
( | ||
req: Request, | ||
res: Response, | ||
next: (error?: any) => void | Promise<void> | ||
): void; | ||
} | ||
``` | ||
An example using `cors`: | ||
```ts | ||
import { use } from "next-api-middleware"; | ||
import cors from "cors"; | ||
export const withMiddleware = use( | ||
// Asserting express/connect middleware as an `ExpressMiddleware` interface | ||
// can resolve type conflicts by libraries that provide their own types. | ||
cors() as ExpressMiddleware | ||
); | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17291
276