API-Routen

Beispiele

Gut zu wissen: Wenn Sie den App-Router verwenden, können Sie Server Components oder Route Handlers anstelle von API-Routen nutzen.

API-Routen bieten eine Lösung zum Erstellen einer öffentlichen API mit Next.js.

Jede Datei im Ordner pages/api wird auf /api/* gemappt und als API-Endpunkt anstelle einer page behandelt. Es handelt sich um serverseitige Bundles, die die clientseitige Bundle-Größe nicht erhöhen.

Beispielsweise gibt die folgende API-Route eine JSON-Antwort mit dem Statuscode 200 zurück:

import type { NextApiRequest, NextApiResponse } from 'next'

type ResponseData = {
  message: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Gut zu wissen:

Parameter

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // ...
}

HTTP-Methoden

Um verschiedene HTTP-Methoden in einer API-Route zu verarbeiten, können Sie req.method in Ihrem Request-Handler verwenden:

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // Verarbeite einen POST-Request
  } else {
    // Behandle jede andere HTTP-Methode
  }
}
export default function handler(req, res) {
  if (req.method === 'POST') {
    // Verarbeite einen POST-Request
  } else {
    // Behandle jede andere HTTP-Methode
  }
}

Request-Helper

API-Routen bieten eingebaute Request-Helper, die den eingehenden Request (req) parsen:

  • req.cookies - Ein Objekt mit den vom Request gesendeten Cookies. Standardwert: {}
  • req.query - Ein Objekt mit der Query-String. Standardwert: {}
  • req.body - Ein Objekt mit dem durch content-type geparsten Body oder null, wenn kein Body gesendet wurde

Benutzerdefinierte Konfiguration

Jede API-Route kann ein config-Objekt exportieren, um die Standardkonfiguration zu ändern:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // Gibt die maximal erlaubte Ausführungsdauer für diese Funktion an (in Sekunden)
  maxDuration: 5,
}

bodyParser ist standardmäßig aktiviert. Wenn Sie den Body als Stream oder mit raw-body verarbeiten möchten, können Sie dies auf false setzen.

Ein Anwendungsfall für das Deaktivieren des automatischen bodyParsing ist die Validierung des Roh-Bodys eines Webhook-Requests, z.B. von GitHub.

export const config = {
  api: {
    bodyParser: false,
  },
}

bodyParser.sizeLimit ist die maximale Größe des geparsten Bodys in einem von bytes unterstützten Format:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '500kb',
    },
  },
}

externalResolver ist ein explizites Flag, das dem Server mitteilt, dass diese Route von einem externen Resolver wie express oder connect behandelt wird. Das Aktivieren dieser Option deaktiviert Warnungen für ungelöste Requests.

export const config = {
  api: {
    externalResolver: true,
  },
}

responseLimit ist standardmäßig aktiviert und warnt, wenn der Response-Body einer API-Route 4MB überschreitet.

Wenn Sie Next.js nicht in einer serverlosen Umgebung verwenden und die Leistungsauswirkungen verstehen, können Sie dieses Limit auf false setzen.

export const config = {
  api: {
    responseLimit: false,
  },
}

responseLimit kann auch eine Byte-Anzahl oder ein von bytes unterstütztes String-Format annehmen, z.B. 1000, '500kb' oder '3mb'. Dieser Wert ist die maximale Response-Größe, bevor eine Warnung angezeigt wird. Standard ist 4MB.

export const config = {
  api: {
    responseLimit: '8mb',
  },
}

Response-Helper

Das Server Response-Objekt (oft als res abgekürzt) enthält eine Reihe von Express.js-ähnlichen Hilfsfunktionen, die die Entwicklererfahrung verbessern und die Erstellung neuer API-Endpunkte beschleunigen.

Die enthaltenen Helfer sind:

  • res.status(code) - Eine Funktion zum Setzen des Statuscodes. code muss ein gültiger HTTP-Statuscode sein
  • res.json(body) - Sendet eine JSON-Antwort. body muss ein serialisierbares Objekt sein
  • res.send(body) - Sendet die HTTP-Antwort. body kann ein string, ein object oder ein Buffer sein
  • res.redirect([status,] path) - Leitet zu einem bestimmten Pfad oder URL weiter. status muss ein gültiger HTTP-Statuscode sein. Wenn nicht angegeben, ist der Standardwert "307" "Temporary redirect".
  • res.revalidate(urlPath) - Revalidiert eine Seite bei Bedarf mit getStaticProps. urlPath muss ein string sein.

Setzen des Statuscodes einer Antwort

Beim Senden einer Antwort an den Client können Sie den Statuscode der Antwort setzen.

Das folgende Beispiel setzt den Statuscode der Antwort auf 200 (OK) und gibt eine message-Eigenschaft mit dem Wert Hello from Next.js! als JSON-Antwort zurück:

import type { NextApiRequest, NextApiResponse } from 'next'

type ResponseData = {
  message: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Senden einer JSON-Antwort

Beim Senden einer Antwort an den Client können Sie eine JSON-Antwort senden, die ein serialisierbares Objekt sein muss. In einer realen Anwendung möchten Sie möglicherweise den Client über den Status des Requests informieren, abhängig vom Ergebnis des angeforderten Endpunkts.

Das folgende Beispiel sendet eine JSON-Antwort mit dem Statuscode 200 (OK) und dem Ergebnis der asynchronen Operation. Es ist in einem try-catch-Block enthalten, um mögliche Fehler zu behandeln, mit dem entsprechenden Statuscode und der Fehlermeldung, die an den Client zurückgesendet wird:

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).json({ result })
  } catch (err) {
    res.status(500).json({ error: 'failed to load data' })
  }
}
export default async function handler(req, res) {
  try {
    const result = await someAsyncOperation()
    res.status(200).json({ result })
  } catch (err) {
    res.status(500).json({ error: 'failed to load data' })
  }
}

Senden einer HTTP-Antwort

Das Senden einer HTTP-Antwort funktioniert genauso wie das Senden einer JSON-Antwort. Der einzige Unterschied besteht darin, dass der Antwort-Body ein string, ein object oder ein Buffer sein kann.

Das folgende Beispiel sendet eine HTTP-Antwort mit dem Statuscode 200 (OK) und dem Ergebnis der asynchronen Operation.

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).send({ result })
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}
export default async function handler(req, res) {
  try {
    const result = await someAsyncOperation()
    res.status(200).send({ result })
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}

Weiterleitung zu einem bestimmten Pfad oder URL

Nehmen wir ein Formular als Beispiel: Sie möchten Ihren Client nach erfolgreicher Übermittlung des Formulars zu einem bestimmten Pfad oder URL weiterleiten.

Das folgende Beispiel leitet den Client zum Pfad / weiter, wenn das Formular erfolgreich übermittelt wurde:

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { name, message } = req.body

  try {
    await handleFormInputAsync({ name, message })
    res.redirect(307, '/')
  } catch (err) {
    res.status(500).send({ error: 'Failed to fetch data' })
  }
}
export default async function handler(req, res) {
  const { name, message } = req.body

  try {
    await handleFormInputAsync({ name, message })
    res.redirect(307, '/')
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}

Hinzufügen von TypeScript-Typen

Sie können Ihre API-Routen typsicher machen, indem Sie die Typen NextApiRequest und NextApiResponse aus next importieren. Zusätzlich können Sie auch Ihre Antwortdaten typisieren:

import type { NextApiRequest, NextApiResponse } from 'next'

type ResponseData = {
  message: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Gut zu wissen: Der Body von NextApiRequest ist any, da der Client beliebige Daten senden kann. Sie sollten den Typ/die Form des Bodys zur Laufzeit validieren, bevor Sie ihn verwenden.

Dynamische API-Routen

API-Routen unterstützen dynamische Routen und folgen denselben Dateibenennungsregeln wie pages/.

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}
export default function handler(req, res) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}

Eine Anfrage an /api/post/abc antwortet nun mit dem Text: Post: abc.

Catch-all-API-Routen

API-Routen können erweitert werden, um alle Pfade abzufangen, indem drei Punkte (...) in den Klammern hinzugefügt werden. Beispiel:

  • pages/api/post/[...slug].js matcht /api/post/a, aber auch /api/post/a/b, /api/post/a/b/c usw.

Gut zu wissen: Sie können andere Namen als slug verwenden, z.B. [...param]

Die gematchten Parameter werden als Query-Parameter (slug im Beispiel) an die Seite gesendet und sind immer ein Array. Der Pfad /api/post/a hat also folgendes query-Objekt:

{ "slug": ["a"] }

Und im Fall von /api/post/a/b oder jedem anderen passenden Pfad werden neue Parameter zum Array hinzugefügt:

{ "slug": ["a", "b"] }

Beispiel:

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}
export default function handler(req, res) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}

Eine Anfrage an /api/post/a/b/c antwortet nun mit dem Text: Post: a, b, c.

Optionale Catch-all-API-Routen

Catch-all-Routen können optional gemacht werden, indem der Parameter in doppelte Klammern gesetzt wird ([[...slug]]).

Beispiel: pages/api/post/[[...slug]].js matcht /api/post, /api/post/a, /api/post/a/b usw.

Der Hauptunterschied zwischen Catch-all- und optionalen Catch-all-Routen besteht darin, dass bei optionalen Routen auch der Pfad ohne Parameter gematcht wird (/api/post im obigen Beispiel).

Die query-Objekte sehen wie folgt aus:

{ } // GET `/api/post` (leeres Objekt)
{ "slug": ["a"] } // `GET /api/post/a` (Array mit einem Element)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (Array mit mehreren Elementen)

Caveats

  • Vordefinierte API-Routen haben Vorrang vor dynamischen API-Routen, und dynamische API-Routen haben Vorrang vor Catch-all-API-Routen. Beispiele:
    • pages/api/post/create.js - Matcht /api/post/create
    • pages/api/post/[pid].js - Matcht /api/post/1, /api/post/abc usw., aber nicht /api/post/create
    • pages/api/post/[...slug].js - Matcht /api/post/1/2, /api/post/a/b/c usw., aber nicht /api/post/create, /api/post/abc

Edge-API-Routen

Wenn Sie API-Routen mit der Edge Runtime verwenden möchten, empfehlen wir die schrittweise Einführung des App-Routers und die Verwendung von Route Handlers anstelle von API-Routen.

Die Funktionssignatur von Route Handlern ist isomorph, was bedeutet, dass Sie dieselbe Funktion für sowohl Edge- als auch Node.js-Runtimes verwenden können.