Rutas API

Ejemplos

Es bueno saberlo: Si estás usando el App Router, puedes utilizar Componentes del Servidor o Manejadores de Ruta en lugar de Rutas API.

Las rutas API proporcionan una solución para construir una API pública con Next.js.

Cualquier archivo dentro de la carpeta pages/api se mapea a /api/* y será tratado como un endpoint API en lugar de una página. Son bundles exclusivos del lado del servidor y no aumentarán el tamaño de tu bundle del lado del cliente.

Por ejemplo, la siguiente ruta API devuelve una respuesta JSON con un código de estado 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!' })
}

Es bueno saberlo:

Parámetros

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

Métodos HTTP

Para manejar diferentes métodos HTTP en una ruta API, puedes usar req.method en tu manejador de solicitudes, así:

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // Procesar una solicitud POST
  } else {
    // Manejar cualquier otro método HTTP
  }
}

Helpers de Solicitud

Las Rutas API proporcionan helpers de solicitud integrados que analizan la solicitud entrante (req):

  • req.cookies - Un objeto que contiene las cookies enviadas por la solicitud. Por defecto {}
  • req.query - Un objeto que contiene la cadena de consulta. Por defecto {}
  • req.body - Un objeto que contiene el cuerpo analizado por content-type, o null si no se envió cuerpo

Configuración personalizada

Cada Ruta API puede exportar un objeto config para cambiar la configuración predeterminada, que es la siguiente:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // Especifica la duración máxima permitida para que esta función se ejecute (en segundos)
  maxDuration: 5,
}

bodyParser está habilitado automáticamente. Si deseas consumir el cuerpo como un Stream o con raw-body, puedes establecer esto en false.

Un caso de uso para deshabilitar el bodyParsing automático es permitirte verificar el cuerpo crudo de una solicitud de webhook, por ejemplo desde GitHub.

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

bodyParser.sizeLimit es el tamaño máximo permitido para el cuerpo analizado, en cualquier formato soportado por bytes, así:

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

externalResolver es una bandera explícita que le indica al servidor que esta ruta está siendo manejada por un resolvedor externo como express o connect. Habilitar esta opción desactiva las advertencias para solicitudes no resueltas.

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

responseLimit está habilitado automáticamente, advirtiendo cuando el cuerpo de respuesta de una Ruta API supera los 4MB.

Si no estás usando Next.js en un entorno sin servidor, y entiendes las implicaciones de rendimiento de no usar un CDN o un host de medios dedicado, puedes establecer este límite en false.

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

responseLimit también puede tomar el número de bytes o cualquier formato de cadena soportado por bytes, por ejemplo 1000, '500kb' o '3mb'. Este valor será el tamaño máximo de respuesta antes de que se muestre una advertencia. Por defecto es 4MB. (ver arriba)

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

Helpers de Respuesta

El objeto Server Response, (a menudo abreviado como res) incluye un conjunto de métodos helpers al estilo de Express.js para mejorar la experiencia del desarrollador y aumentar la velocidad de creación de nuevos endpoints API.

Los helpers incluidos son:

  • res.status(código) - Una función para establecer el código de estado. código debe ser un código de estado HTTP válido
  • res.json(cuerpo) - Envía una respuesta JSON. cuerpo debe ser un objeto serializable
  • res.send(cuerpo) - Envía la respuesta HTTP. cuerpo puede ser un string, un objeto o un Buffer
  • res.redirect([estado,] ruta) - Redirige a una ruta o URL específica. estado debe ser un código de estado HTTP válido. Si no se especifica, estado por defecto es "307" "Redirección temporal".
  • res.revalidate(rutaURL) - Revalida una página bajo demanda usando getStaticProps. rutaURL debe ser un string.

Estableciendo el código de estado de una respuesta

Al enviar una respuesta al cliente, puedes establecer el código de estado de la respuesta.

El siguiente ejemplo establece el código de estado de la respuesta en 200 (OK) y devuelve una propiedad message con el valor de Hello from Next.js! como respuesta 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!' })
}

Enviando una respuesta JSON

Al enviar una respuesta al cliente puedes enviar una respuesta JSON, esta debe ser un objeto serializable. En una aplicación del mundo real, es posible que desees informar al cliente sobre el estado de la solicitud dependiendo del resultado del endpoint solicitado.

El siguiente ejemplo envía una respuesta JSON con el código de estado 200 (OK) y el resultado de la operación asíncrona. Está contenido en un bloque try catch para manejar cualquier error que pueda ocurrir, con el código de estado apropiado y el mensaje de error capturado y enviado de vuelta al cliente:

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

Enviando una respuesta HTTP

Enviar una respuesta HTTP funciona de la misma manera que enviar una respuesta JSON. La única diferencia es que el cuerpo de la respuesta puede ser un string, un objeto o un Buffer.

El siguiente ejemplo envía una respuesta HTTP con el código de estado 200 (OK) y el resultado de la operación asíncrona.

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

Redirigiendo a una ruta o URL específica

Tomando un formulario como ejemplo, es posible que desees redirigir a tu cliente a una ruta o URL específica una vez que hayan enviado el formulario.

El siguiente ejemplo redirige al cliente a la ruta / si el formulario se envía correctamente:

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

Añadiendo tipos TypeScript

Puedes hacer tus Rutas API más seguras en cuanto a tipos importando los tipos NextApiRequest y NextApiResponse desde next, además de esos, también puedes tipar tus datos de respuesta:

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

Es bueno saberlo: El cuerpo de NextApiRequest es any porque el cliente puede incluir cualquier carga útil. Debes validar el tipo/forma del cuerpo en tiempo de ejecución antes de usarlo.

Rutas API Dinámicas

Las Rutas API soportan rutas dinámicas, y siguen las mismas reglas de nomenclatura de archivos que se usan para pages/.

import type { NextApiRequest, NextApiResponse } from 'next'

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

Ahora, una solicitud a /api/post/abc responderá con el texto: Post: abc.

Rutas API catch all

Las Rutas API pueden extenderse para capturar todas las rutas añadiendo tres puntos (...) dentro de los corchetes. Por ejemplo:

  • pages/api/post/[...slug].js coincide con /api/post/a, pero también con /api/post/a/b, /api/post/a/b/c y así sucesivamente.

Es bueno saberlo: Puedes usar nombres distintos a slug, como: [...param]

Los parámetros coincidentes se enviarán como un parámetro de consulta (slug en el ejemplo) a la página, y siempre será un array, por lo que la ruta /api/post/a tendrá el siguiente objeto query:

{ "slug": ["a"] }

Y en el caso de /api/post/a/b, y cualquier otra ruta coincidente, se añadirán nuevos parámetros al array, así:

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

Por ejemplo:

import type { NextApiRequest, NextApiResponse } from 'next'

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

Ahora, una solicitud a /api/post/a/b/c responderá con el texto: Post: a, b, c.

Rutas API catch all opcionales

Las rutas catch all pueden hacerse opcionales incluyendo el parámetro en dobles corchetes ([[...slug]]).

Por ejemplo, pages/api/post/[[...slug]].js coincidirá con /api/post, /api/post/a, /api/post/a/b, y así sucesivamente.

La principal diferencia entre las rutas catch all y catch all opcionales es que con las opcionales, la ruta sin el parámetro también coincide (/api/post en el ejemplo anterior).

Los objetos query son los siguientes:

{ } // GET `/api/post` (objeto vacío)
{ "slug": ["a"] } // `GET /api/post/a` (array de un elemento)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (array de múltiples elementos)

Consideraciones

  • Las rutas API predefinidas tienen prioridad sobre las rutas API dinámicas, y las rutas API dinámicas sobre las rutas API catch all. Mira los siguientes ejemplos:
    • pages/api/post/create.js - Coincidirá con /api/post/create
    • pages/api/post/[pid].js - Coincidirá con /api/post/1, /api/post/abc, etc. Pero no con /api/post/create
    • pages/api/post/[...slug].js - Coincidirá con /api/post/1/2, /api/post/a/b/c, etc. Pero no con /api/post/create, /api/post/abc

Respuestas en streaming

Si bien el Pages Router soporta respuestas en streaming con Rutas API, recomendamos adoptar incrementalmente el App Router y usar Manejadores de Ruta si estás en Next.js 14+.

Aquí te mostramos cómo puedes transmitir una respuesta desde una Ruta API con 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()
}