Routes API

Exemples

Bon à savoir : Si vous utilisez le routeur d'application (App Router), vous pouvez utiliser les Composants Serveur ou les Gestionnaires de Route (Route Handlers) à la place des routes API.

Les routes API offrent une solution pour construire une API publique avec Next.js.

Tout fichier situé dans le dossier pages/api est mappé vers /api/* et sera traité comme un point de terminaison d'API plutôt que comme une page. Ce sont des bundles exclusivement côté serveur qui n'augmenteront pas la taille de votre bundle côté client.

Par exemple, la route API suivante renvoie une réponse JSON avec un code de statut 200 :

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!' })
}

Bon à savoir :

Paramètres

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

Méthodes HTTP

Pour gérer différentes méthodes HTTP dans une route API, vous pouvez utiliser req.method dans votre gestionnaire de requête, comme ceci :

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // Traiter une requête POST
  } else {
    // Gérer toute autre méthode HTTP
  }
}

Helpers de Requête

Les routes API fournissent des helpers de requête intégrés qui analysent la requête entrante (req) :

  • req.cookies - Un objet contenant les cookies envoyés par la requête. Par défaut {}
  • req.query - Un objet contenant la chaîne de requête (query string). Par défaut {}
  • req.body - Un objet contenant le corps analysé par content-type, ou null si aucun corps n'a été envoyé

Configuration personnalisée

Chaque route API peut exporter un objet config pour modifier la configuration par défaut, qui est la suivante :

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // Spécifie la durée maximale autorisée pour l'exécution de cette fonction (en secondes)
  maxDuration: 5,
}

bodyParser est activé automatiquement. Si vous souhaitez consommer le corps comme un Stream ou avec raw-body, vous pouvez le désactiver en le définissant sur false.

Un cas d'utilisation pour désactiver le bodyParser automatique est de vous permettre de vérifier le corps brut d'une requête webhook, par exemple depuis GitHub.

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

bodyParser.sizeLimit est la taille maximale autorisée pour le corps analysé, dans n'importe quel format pris en charge par bytes, comme ceci :

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

externalResolver est un drapeau explicite qui indique au serveur que cette route est gérée par un résolveur externe comme express ou connect. Activer cette option désactive les avertissements pour les requêtes non résolues.

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

responseLimit est activé automatiquement, avertissant lorsque le corps de la réponse d'une route API dépasse 4 Mo.

Si vous n'utilisez pas Next.js dans un environnement serverless, et que vous comprenez les implications en termes de performance de ne pas utiliser un CDN ou un hébergement média dédié, vous pouvez désactiver cette limite en la définissant sur false.

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

responseLimit peut également prendre un nombre d'octets ou toute chaîne de format prise en charge par bytes, par exemple 1000, '500kb' ou '3mb'. Cette valeur sera la taille maximale de la réponse avant qu'un avertissement ne s'affiche. Par défaut, c'est 4 Mo (voir ci-dessus).

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

Helpers de Réponse

L'objet Réponse du Serveur, (souvent abrégé en res) inclut un ensemble de méthodes helpers de type Express.js pour améliorer l'expérience du développeur et accélérer la création de nouveaux points de terminaison d'API.

Les helpers inclus sont :

  • res.status(code) - Une fonction pour définir le code de statut. code doit être un code de statut HTTP valide
  • res.json(body) - Envoie une réponse JSON. body doit être un objet sérialisable
  • res.send(body) - Envoie la réponse HTTP. body peut être une string, un object ou un Buffer
  • res.redirect([status,] path) - Redirige vers un chemin ou une URL spécifiée. status doit être un code de statut HTTP valide. Si non spécifié, status est par défaut "307" "Redirection temporaire".
  • res.revalidate(urlPath) - Revalider une page à la demande en utilisant getStaticProps. urlPath doit être une string.

Définir le code de statut d'une réponse

Lors de l'envoi d'une réponse au client, vous pouvez définir le code de statut de la réponse.

L'exemple suivant définit le code de statut de la réponse à 200 (OK) et renvoie une propriété message avec la valeur Hello from Next.js! comme réponse JSON :

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!' })
}

Envoyer une réponse JSON

Lors de l'envoi d'une réponse au client, vous pouvez envoyer une réponse JSON, qui doit être un objet sérialisable. Dans une application réelle, vous pourriez vouloir informer le client du statut de la requête en fonction du résultat du point de terminaison demandé.

L'exemple suivant envoie une réponse JSON avec le code de statut 200 (OK) et le résultat de l'opération asynchrone. Il est contenu dans un bloc try catch pour gérer les erreurs qui pourraient survenir, avec le code de statut approprié et le message d'erreur capturé et renvoyé au client :

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' })
  }
}

Envoyer une réponse HTTP

L'envoi d'une réponse HTTP fonctionne de la même manière que l'envoi d'une réponse JSON. La seule différence est que le corps de la réponse peut être une string, un object ou un Buffer.

L'exemple suivant envoie une réponse HTTP avec le code de statut 200 (OK) et le résultat de l'opération asynchrone.

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' })
  }
}

Rediriger vers un chemin ou une URL spécifié

Prenons un formulaire comme exemple, vous pourriez vouloir rediriger votre client vers un chemin ou une URL spécifié une fois qu'il a soumis le formulaire.

L'exemple suivant redirige le client vers le chemin / si le formulaire est soumis avec succès :

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' })
  }
}

Ajouter des types TypeScript

Vous pouvez rendre vos routes API plus typées en important les types NextApiRequest et NextApiResponse depuis next, en plus de ceux-ci, vous pouvez également typer vos données de réponse :

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!' })
}

Bon à savoir : Le corps de NextApiRequest est any car le client peut inclure n'importe quelle charge utile. Vous devriez valider le type/la forme du corps à l'exécution avant de l'utiliser.

Routes API Dynamiques

Les routes API prennent en charge les routes dynamiques, et suivent les mêmes règles de nommage de fichiers utilisées pour pages/.

import type { NextApiRequest, NextApiResponse } from 'next'

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

Maintenant, une requête vers /api/post/abc répondra avec le texte : Post: abc.

Routes API attrape-tout (Catch all)

Les routes API peuvent être étendues pour attraper tous les chemins en ajoutant trois points (...) à l'intérieur des crochets. Par exemple :

  • pages/api/post/[...slug].js correspond à /api/post/a, mais aussi à /api/post/a/b, /api/post/a/b/c, etc.

Bon à savoir : Vous pouvez utiliser d'autres noms que slug, comme : [...param]

Les paramètres correspondants seront envoyés comme paramètre de requête (slug dans l'exemple) à la page, et ce sera toujours un tableau, donc, le chemin /api/post/a aura l'objet query suivant :

{ "slug": ["a"] }

Et dans le cas de /api/post/a/b, et tout autre chemin correspondant, de nouveaux paramètres seront ajoutés au tableau, comme ceci :

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

Par exemple :

import type { NextApiRequest, NextApiResponse } from 'next'

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

Maintenant, une requête vers /api/post/a/b/c répondra avec le texte : Post: a, b, c.

Routes API attrape-tout optionnelles (Optional catch all)

Les routes attrape-tout peuvent être rendues optionnelles en incluant le paramètre dans des doubles crochets ([[...slug]]).

Par exemple, pages/api/post/[[...slug]].js correspondra à /api/post, /api/post/a, /api/post/a/b, etc.

La principale différence entre les routes attrape-tout et attrape-tout optionnelles est qu'avec les optionnelles, la route sans le paramètre est également correspondante (/api/post dans l'exemple ci-dessus).

Les objets query sont les suivants :

{ } // GET `/api/post` (objet vide)
{ "slug": ["a"] } // `GET /api/post/a` (tableau à un élément)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (tableau à plusieurs éléments)

Mises en garde

  • Les routes API prédéfinies prennent le pas sur les routes API dynamiques, et les routes API dynamiques prennent le pas sur les routes API attrape-tout. Regardez les exemples suivants :
    • pages/api/post/create.js - Correspondra à /api/post/create
    • pages/api/post/[pid].js - Correspondra à /api/post/1, /api/post/abc, etc. Mais pas à /api/post/create
    • pages/api/post/[...slug].js - Correspondra à /api/post/1/2, /api/post/a/b/c, etc. Mais pas à /api/post/create, /api/post/abc

Réponses en streaming

Bien que le routeur de pages (Pages Router) prenne en charge les réponses en streaming avec les routes API, nous recommandons d'adopter progressivement le routeur d'application (App Router) et d'utiliser les Gestionnaires de Route (Route Handlers) si vous êtes sur Next.js 14+.

Voici comment vous pouvez diffuser une réponse depuis une route API avec writeHead :

pages/api/hello.js
import { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': "no-store",
  })
  let i = 0
  while (i < 10) {
    res.write(`data: ${i}\n\n`)
    i++
    await new Promise((resolve) => setTimeout(resolve, 1000))
  }
  res.end()
}