️ Esta biblioteca fue escrita para admitir rutas API que usan el enrutador de páginas Next.js. No se ha probado con el enrutador de la aplicación.
Las rutas API de Next.JS son una forma ridículamente divertida y simple de agregar funcionalidad de backend a una aplicación React. Sin embargo, cuando llega el momento de agregar middleware, no hay una manera fácil de implementarlo.
Los documentos oficiales de Next.JS recomiendan escribir funciones dentro de su manejador de ruta API. Este es un gran paso atrás en comparación con las API limpias proporcionadas por express.js o koa.js.
Esta biblioteca intenta proporcionar patrones de middleware mínimos, limpios y compuestos que son productivos y agradables de usar.
labeluse import { label , Middleware } from "next-api-middleware" ;
import * as Sentry from "@sentry/nextjs" ;
import nanoid from "nanoid" ;
// 1 – Create middleware functions
const captureErrors : Middleware = async ( req , res , next ) => {
try {
// Catch any errors that are thrown in remaining
// middleware and the API route handler
await next ( ) ;
} catch ( err ) {
const eventId = Sentry . captureException ( err ) ;
res . status ( 500 ) ;
res . json ( { error : err } ) ;
}
} ;
const addRequestId : Middleware = async ( req , res , next ) => {
// Let remaining middleware and API route execute
await next ( ) ;
// Apply header
res . setHeader ( "X-Response-ID" , nanoid ( ) ) ;
} ;
// 2 – Use `label` to assemble all middleware
const withMiddleware = label (
{
addRequestId ,
sentry : captureErrors , // <-- Optionally alias middleware
} ,
[ "sentry" ] // <-- Provide a list of middleware to call automatically
) ;
// 3 – Define your API route handler
const apiRouteHandler = async ( req , res ) => {
res . status ( 200 ) ;
res . send ( "Hello world!" ) ;
} ;
// 4 – Choose middleware to invoke for this API route
export default withMiddleware ( "addRequestId" ) ( apiRouteHandler ) ; Mi modelo mental sobre cómo esta biblioteca maneja las funciones de middleware es el de una "pila de sinuosos y desenrollando".
Imaginemos que ha usado label para agregar dos funciones de middleware a una ruta API.
Cuando entra una solicitud, esta es una impresión aproximada de cómo esa solicitud se abre paso a través de todas las funciones de middleware, el manejador de ruta API en sí y luego retrocede a través del middleware.
|-----------------|-----------------|--------------------|
| Middleware #1 | Middleware #2 | API Route Handler |
|-----------------|-----------------|--------------------|
| | | |
Request ------|----> Setup -----|----> Setup -----|-->------| |
| | | | |
|-----------------|-----------------| V |
| | | |
| await next() | await next() | API stuff |
| | | |
|-----------------|-----------------| | |
| | | | |
Response <----|--- Teardown <---|--- Teardown <---|---------| |
| | | |
|-----------------|-----------------|--------------------|
Si bien este es un diagrama ASCII de mal humor, creo que da la impresión correcta. La solicitud entra en su camino a través de cada función de middleware en sucesión, golpea el manejador de ruta API y luego procede a "relajarse" a través de la pila.
Cada función de middleware tiene la oportunidad de pasar por tres fases:
La fase "Configuración" cubre todo lo que sucede antes de await next() . La fase de "espera" realmente es solo await next() . La fase de "desmontaje" es el código restante dentro de una función de middleware después de await next() .
Vale la pena señalar que aunque estas fases están disponibles para todas las funciones de middleware, no necesita aprovecharlas de todas.
Por ejemplo, en un error de captura de middleware, simplemente puede envolverlo await next() en un bloque de try / catch . Por otro lado, es posible que tenga un middleware de tiempo de solicitud que capture una hora de inicio durante la fase de configuración, espera y luego captura un tiempo de finalización en la fase de desmontaje.
labelEsta es la utilidad principal para crear colecciones reusables de middleware para su uso en muchas rutas API de Next.js.
const withMiddleware = label ( middleware , defaults ) ; middleware : un objeto que contiene funciones de middleware o matrices de middlewaredefaults : (opcional) Una matriz de claves middleware que se invocarán automáticamente label devuelve una función (mencionada convencionalmente como withMiddleware ) que usa el currying para aceptar una lista de nombres de middleware para ser invocados, seguido de una función Next.js API Handler.
Por lo general, withMiddleware se importará en archivos de ruta API y se utilizará en la declaración de exportación predeterminada:
import { withMiddleware } from "../helpers/my-middleware" ;
const apiRouteHandler = async ( req , res ) => {
...
}
export default withMiddleware ( "foo" , "bar" , "baz" ) ( apiRouteHandler ) ; Aunque label podría contener muchas funciones de middleware, el middleware real invocado por una ruta API está determinado por los nombres pasados a withMiddleware .
const logErrors = async ( req , res , next ) => {
try {
await next ( ) ;
} catch ( error ) {
console . error ( error ) ;
res . status ( 500 ) ;
res . json ( { error } ) ;
}
} ;
const withMiddleware = label ( {
logErrors ,
} ) ;
// export default withMiddleware("logErrors")(apiRouteHandler); const withMiddleware = label ( {
error : logErrors ,
} ) ;
// export default withMiddleware("error")(apiRouteHandler); import { foo , bar , baz } from "./my-middleware" ;
const withMiddleware = label ( {
error : logErrors ,
myGroup : [ foo , bar , baz ] ,
} ) ;
// export default withMiddleware("error", "myGroup")(apiRouteHandler); const withMiddleware = label (
{
error : logErrors ,
myGroup : [ foo , bar , baz ] ,
} ,
[ "error" ]
) ;
// export default withMiddleware("myGroup")(apiRouteHandler);use Esta utilidad acepta funciones de middleware directamente y las ejecuta todas en orden. Es una alternativa más simple a label que puede ser útil para manejar funciones únicas de middleware.
const withInlineMiddleware = use ( ... middleware ) ; middleware : una lista de funciones de middleware y/o matrices de funciones de middleware use devuelve una función que acepta un manejador de ruta API Next.js.
import { use } from "next-api-middleware" ;
import cors from "cors" ;
const apiRouteThatOnlyNeedsCORS = async ( req , res ) => {
...
}
export default use ( cors ( ) ) ( apiRouteThatOnlyNeedsCORS ) ; Consulte Ejemplos.MD para ver ejemplos más detallados de label y use .
Dado que use y label aceptan valores que evalúan las funciones de middleware, esto brinda la oportunidad de crear fábricas de middleware personalizadas.
Aquí hay un ejemplo de una fábrica que genera una función de middleware para permitir solo solicitudes con un método HTTP dado:
import { Middleware } from "next-api-middleware" ;
const httpMethod = (
allowedHttpMethod : "GET" | "POST" | "PATCH"
) : Middleware => {
return async function ( req , res , next ) {
if ( req . method === allowedHttpMethod || req . method == "OPTIONS" ) {
await next ( ) ;
} else {
res . status ( 404 ) ;
res . end ( ) ;
}
} ;
} ;
export const postRequestsOnlyMiddleware = httpMethod ( "POST" ) ; Middleware está inspirado en el estilo de middleware asíncrono popularizado por Koa.js.
type Middleware < Request = NextApiRequest , Response = NextApiResponse > = (
req : Request ,
res : Response ,
next : ( ) => Promise < void >
) => Promise < void > ;