️ Esta biblioteca foi gravada para oferecer suporte a rotas de API que usam o roteador Next.JS Pages. Não foi testado com o roteador de aplicativos.
As rotas da API do próximo.js são uma maneira ridiculamente divertida e simples de adicionar funcionalidade de back -end a um aplicativo React. No entanto, quando chega a hora de adicionar middleware, não há uma maneira fácil de implementá -lo.
Os documentos oficiais do próximo.js recomendam escrever funções dentro do seu manipulador de rota da API. Este é um grande passo para trás em comparação com as APIs limpas fornecidas pelo Express.js ou Koa.js.
Esta biblioteca tenta fornecer padrões mínimos, limpos e composíveis de middleware que são produtivos e agradáveis 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 ) ; Meu modelo mental de como essa biblioteca lida com as funções do middleware é a de uma "pilha sinuosa e desenrolada".
Vamos imaginar que você usou label para adicionar duas funções de middleware a uma rota da API.
Quando uma solicitação entra, essa é uma impressão aproximada de como essa solicitação passa por todas as funções de middleware, o próprio manipulador de rota da API e depois volta pelo middleware.
|-----------------|-----------------|--------------------|
| Middleware #1 | Middleware #2 | API Route Handler |
|-----------------|-----------------|--------------------|
| | | |
Request ------|----> Setup -----|----> Setup -----|-->------| |
| | | | |
|-----------------|-----------------| V |
| | | |
| await next() | await next() | API stuff |
| | | |
|-----------------|-----------------| | |
| | | | |
Response <----|--- Teardown <---|--- Teardown <---|---------| |
| | | |
|-----------------|-----------------|--------------------|
Embora este seja um diagrama ASCII ruim, acho que dá a impressão certa. A solicitação encerra seu caminho, embora cada middleware funcione em sucessão, atinge o manipulador de rota da API e depois passa a "relaxar" o caminho pela pilha.
Toda função de middleware tem a oportunidade de passar por três fases:
A fase "Configuração" cobre tudo o que acontece antes de await next() . A fase "esperando" é realmente apenas await next() . A fase de "desmontagem" é o código restante dentro de uma função de middleware após await next() .
Vale ressaltar que, embora essas fases estejam disponíveis para todas as funções de middleware, você não precisa aproveitar todas elas.
Por exemplo, no erro de captura de middleware, você pode simplesmente envolver await next() em um bloco de try / catch . Por outro lado, você pode solicitar que o Middleware do tempo de solicitação que capture um horário de início durante a fase de instalação, aguarda e, em seguida, captura um horário de acabamento na fase de desmontagem.
labelEssa é a principal utilidade para criar coleções reutilizáveis de middleware para uso em muitas rotas da API Next.js.
const withMiddleware = label ( middleware , defaults ) ; middleware : um objeto contendo funções ou matrizes de middleware de middlewaredefaults : (opcional) Uma variedade de chaves middleware que serão invocadas automaticamente label retorna uma função (convencionalmente referida como withMiddleware ) que usa o curry para aceitar uma lista de nomes de middleware a serem chamados, seguidos por uma função de manipulador de API Next.js.
Normalmente, withMiddleware será importado em arquivos de rota da API e usado na instrução EXPORTE PADRÃO:
import { withMiddleware } from "../helpers/my-middleware" ;
const apiRouteHandler = async ( req , res ) => {
...
}
export default withMiddleware ( "foo" , "bar" , "baz" ) ( apiRouteHandler ) ; Embora label possa conter muitas funções de middleware, o middleware real chamado por uma rota da API é determinado pelos nomes passados para 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 Esse utilitário aceita funções de middleware diretamente e as executa em ordem. É uma alternativa mais simples para label que pode ser útil para lidar com funções pontuais de middleware.
const withInlineMiddleware = use ( ... middleware ) ; middleware : uma lista de funções de middleware e/ou matrizes de funções de middleware use retorna uma função que aceita um manipulador de rota da API Next.js.
import { use } from "next-api-middleware" ;
import cors from "cors" ;
const apiRouteThatOnlyNeedsCORS = async ( req , res ) => {
...
}
export default use ( cors ( ) ) ( apiRouteThatOnlyNeedsCORS ) ; Consulte Exemplos.md para obter exemplos mais detalhados de label e use .
Como use e label aceitam valores que avaliam as funções de middleware, isso oferece a oportunidade de criar fábricas personalizadas de middleware.
Aqui está um exemplo de fábrica que gera uma função de middleware para permitir apenas solicitações com um determinado método HTTP:
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 é inspirado no estilo de middleware assíncrono popularizado por koa.js.
type Middleware < Request = NextApiRequest , Response = NextApiResponse > = (
req : Request ,
res : Response ,
next : ( ) => Promise < void >
) => Promise < void > ;