Euen Diese Bibliothek wurde geschrieben, um API -Routen zu unterstützen, die den nächsten.js -Seitenrouter verwenden. Es wurde nicht mit dem App -Router getestet.
NEXT.JS -API -Routen sind eine lächerlich unterhaltsame und einfache Möglichkeit, einer React -App Backend -Funktionalität hinzuzufügen. Wenn es jedoch an der Zeit ist, Middleware hinzuzufügen, gibt es keine einfache Möglichkeit, es zu implementieren.
Die offiziellen Dokumente von Next.js empfehlen, Funktionen in Ihrem API -Routenhandler zu schreiben. Dies ist ein großer Schritt rückwärts im Vergleich zu den sauberen APIs von Express.js oder Koa.js.
Diese Bibliothek versucht, minimale, saubere, komponierbare Middleware -Muster bereitzustellen, die sowohl produktiv als auch angenehm zu bedienen sind.
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 ) ; Mein mentales Modell, wie diese Bibliothek mit Middleware -Funktionen umgeht, ist das eines "Wicklungs- und Abwicklungsstapels".
Stellen Sie uns vor, Sie haben label verwendet, um einer API -Route zwei Middleware -Funktionen hinzuzufügen.
Wenn eine Anfrage eingeht, ist dies ein harter Eindruck davon, wie diese Anfrage durch alle Middleware -Funktionen, den API -Routenhandler selbst und dann durch die Middleware führt.
|-----------------|-----------------|--------------------|
| Middleware #1 | Middleware #2 | API Route Handler |
|-----------------|-----------------|--------------------|
| | | |
Request ------|----> Setup -----|----> Setup -----|-->------| |
| | | | |
|-----------------|-----------------| V |
| | | |
| await next() | await next() | API stuff |
| | | |
|-----------------|-----------------| | |
| | | | |
Response <----|--- Teardown <---|--- Teardown <---|---------| |
| | | |
|-----------------|-----------------|--------------------|
Während dies ein myRumy ASCII -Diagramm ist, denke ich, dass es den richtigen Eindruck hinterlässt. Die Anfrage schlängelt sich nach Folge, dass jede Middleware -Funktion den API -Routenhandler trifft und dann seinen Weg durch den Stapel "entspannt".
Jede Middleware -Funktion hat die Möglichkeit, drei Phasen zu durchlaufen:
Die "Setup" -Phase deckt alles ab, was passiert, bevor await next() . Die "wartende" Phase await next() . Die "Teardown" -Phase ist der verbleibende Code innerhalb einer Middleware -Funktion nach await next() .
Es ist erwähnenswert, dass diese Phasen, obwohl sie allen Middleware -Funktionen zur Verfügung stehen, nicht alle ausnutzen müssen.
Beispielsweise await next() Sie in einem try / catch -Block möglicherweise ein Fehler mit Middleware. Andererseits haben Sie möglicherweise ein Antrag auf Timing Middleware, die während der Einrichtungsphase eine Startzeit erfasst, wartet und dann eine Endzeit in der Teardown -Phase erfasst.
labelDies ist das primäre Dienstprogramm für die Erstellung von Wiederherstellungssammlungen von Middleware für die Verwendung von API -Routen in vielen Nächsten.js.
const withMiddleware = label ( middleware , defaults ) ; middleware : Ein Objekt, das Middleware -Funktionen oder Arrays von Middleware enthältdefaults : (optional) Eine Reihe von middleware -Schlüssel, die automatisch aufgerufen werden label gibt eine Funktion zurück (konventionell als withMiddleware bezeichnet), die Currying verwendet, um eine Liste von Middleware -Namen zu akzeptieren, die aufgerufen werden sollen, gefolgt von einer NEXT.JS -API -Handlerfunktion.
In der Regel wird withMiddleware in API -Routendateien importiert und in der Standard -Exportanweisung verwendet:
import { withMiddleware } from "../helpers/my-middleware" ;
const apiRouteHandler = async ( req , res ) => {
...
}
export default withMiddleware ( "foo" , "bar" , "baz" ) ( apiRouteHandler ) ; Obwohl label viele Middleware -Funktionen enthalten könnte, wird die tatsächliche Middleware, die von einer API -Route aufgerufen wird, anhand der Namen festgelegt, die in withMiddleware übergeben wurden.
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 Dieses Dienstprogramm akzeptiert Middleware -Funktionen direkt und führt sie alle in Ordnung aus. Es ist eine einfachere Alternative zum label , die für den Umgang mit einmaligen Middleware-Funktionen nützlich sein kann.
const withInlineMiddleware = use ( ... middleware ) ; middleware : Eine Liste von Middleware -Funktionen und/oder Arrays von Middleware -Funktionen use Rückgabe eine Funktion, die einen nächsten.js -API -Routenhandler akzeptiert.
import { use } from "next-api-middleware" ;
import cors from "cors" ;
const apiRouteThatOnlyNeedsCORS = async ( req , res ) => {
...
}
export default use ( cors ( ) ) ( apiRouteThatOnlyNeedsCORS ) ; Weitere detailliertere Beispiele für label und use finden Sie unter Beispiele.md.
Da use und label von Werten akzeptieren, die auf Middleware -Funktionen bewertet werden, bietet dies die Möglichkeit, benutzerdefinierte Middleware -Fabriken zu erstellen.
Hier ist ein Beispiel für eine Fabrik, die eine Middleware -Funktion generiert, um nur Anforderungen mit einer bestimmten HTTP -Methode zuzulassen:
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 ist inspiriert vom asyncronous Middleware -Stil, der von koa.js.
type Middleware < Request = NextApiRequest , Response = NextApiResponse > = (
req : Request ,
res : Response ,
next : ( ) => Promise < void >
) => Promise < void > ;