Rutas API

Ejemplos

Es bueno saberlo: Si está utilizando el App Router, puede usar 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 su 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!' })
}
export default function handler(req, res) {
  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, puede usar req.method en su 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
  }
}
export default function handler(req, res) {
  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 desea consumir el cuerpo como un Stream o con raw-body, puede establecer esto en false.

Un caso de uso para deshabilitar el bodyParser automático es permitirle 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 admitido 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á usando Next.js en un entorno sin servidor y comprende las implicaciones de rendimiento de no usar un CDN o un host de medios dedicado, puede 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 admitido 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 helper al estilo 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(code) - Una función para establecer el código de estado. code debe ser un código de estado HTTP válido
  • res.json(body) - Envía una respuesta JSON. body debe ser un objeto serializable
  • res.send(body) - Envía la respuesta HTTP. body puede ser un string, un object o un Buffer
  • res.redirect([status,] path) - Redirige a una ruta o URL especificada. status debe ser un código de estado HTTP válido. Si no se especifica, status por defecto es "307" "Redirección temporal".
  • res.revalidate(urlPath) - Revalida una página bajo demanda usando getStaticProps. urlPath debe ser un string.

Estableciendo el código de estado de una respuesta

Al enviar una respuesta al cliente, puede 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!' })
}
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

Enviando una respuesta JSON

Al enviar una respuesta al cliente puede enviar una respuesta JSON, esta debe ser un objeto serializable. En una aplicación del mundo real, es posible que desee 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 y mensaje de error apropiados capturados y enviados 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' })
  }
}
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' })
  }
}

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

Redirigiendo a una ruta o URL especificada

Tomando un formulario como ejemplo, es posible que desee redirigir a su 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' })
  }
}
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' })
  }
}

Añadiendo tipos TypeScript

Puede hacer que sus Rutas API sean más seguras en cuanto a tipos importando los tipos NextApiRequest y NextApiResponse de next, además de esos, también puede tipar sus 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. Debe validar el tipo/forma del cuerpo en tiempo de ejecución antes de usarlo.

Rutas API Dinámicas

Las Rutas API admiten 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}`)
}
export default function handler(req, res) {
  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 se pueden extender para capturar todas las rutas agregando 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: Puede usar nombres diferentes 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 agregará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(', ')}`)
}
export default function handler(req, res) {
  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 se pueden hacer 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. Observe 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

Rutas API Edge

Si desea utilizar Rutas API con el Edge Runtime, recomendamos adoptar incrementalmente el App Router y usar Manejadores de Ruta en su lugar.

La firma de la función de los Manejadores de Ruta es isomórfica, lo que significa que puede usar la misma función para ambos entornos de ejecución Edge y Node.js.