Endpoints
Astro te permite crear endpoints personalizados para servir cualquier tipo de datos. Puedes usar esto para generar imágenes, exponer un documento RSS o utilizarlos como rutas de API para construir una API completa para tu sitio.
En sitios generados estáticamente, tus endpoints personalizados se llaman en tiempo de construcción para producir archivos estáticos. Si optas por el modo SSR, los endpoints personalizados se convierten en endpoints del servidor en vivo que se llaman bajo petición. Los endpoints estáticos y de SSR se definen de manera similar, pero los endpoints de SSR admiten características adicionales.
Endpoints de archivos estáticos
Sección titulada “Endpoints de archivos estáticos”Para crear un endpoint personalizado, añade un archivo .js o .ts al directorio /pages. La extensión .js o .ts se eliminará durante el proceso de construcción, por lo que el nombre del archivo debe incluir la extensión de los datos que deseas crear. Por ejemplo, src/pages/data.json.ts construirá un endpoint /data.json.
Los endpoints exportan una función GET (opcionalmente async) que recibe un objeto de contexto con propiedades similares al global Astro. Aquí, devuelve un objeto Response con un name y url, y Astro llamará a esto en tiempo de construcción y utilizará el contenido del cuerpo para generar el archivo.
// Outputs: /builtwith.jsonexport function GET({ params, request }) { return new Response( JSON.stringify({ name: "Astro", url: "https://astro.build/", }), );}Desde Astro v3.0, el objeto Response devuelto ya no tiene que incluir la propiedad encoding. Por ejemplo, para producir una imagen binaria .png:
export async function GET({ params, request }) { const response = await fetch( "https://docs.astro.build/assets/full-logo-light.png", );
return new Response(await response.arrayBuffer());}También puedes obtener seguridad de tipos en las funciones de tus endpoints utilizando el tipo APIRoute con el operador satisfies:
import type { APIRoute } from "astro";
export const GET = (async ({ params, request }) => { /* ... */ }) satisfies APIRoute;Ten en cuenta que los endpoints cuyas URLs incluyen una extensión de archivo (por ejemplo, src/pages/sitemap.xml.ts) solo se pueden acceder sin una barra diagonal final (por ejemplo, /sitemap.xml), independientemente de tu configuración de build.trailingSlash.
params y enrutamiento dinámico
Sección titulada “params y enrutamiento dinámico”Los endpoints admiten las mismas características de enrutamiento dinámico que las páginas. Nombra tu archivo con un nombre de parámetro entre corchetes y exporta una función getStaticPaths(). Luego, puedes acceder al parámetro utilizando la propiedad params pasada a la función del endpoint:
import type { APIRoute } from "astro";
const usernames = ["Sarah", "Chris", "Yan", "Elian"];
export const GET = (({ params, request }) => { const id = params.id;
return new Response( JSON.stringify({ name: usernames[id], }), );}) satisfies APIRoute;
export function getStaticPaths() { return [ { params: { id: "0" } }, { params: { id: "1" } }, { params: { id: "2" } }, { params: { id: "3" } }, ];}Esto generará cuatro endpoints JSON en tiempo de construcción: /api/0.json, /api/1.json, /api/2.json y /api/3.json. El enrutamiento dinámico con endpoints funciona igual que con las páginas. En modo estático, puedes pasar props al endpoint utilizando getStaticPaths(). Sin embargo, con el renderizado bajo demanda, dado que el endpoint es una función y no un componente, no se admite el paso de props.
request
Sección titulada “request”Todos los endpoints reciben una propiedad request, pero en modo estático, solo tienes acceso a request.url. Esto devuelve la URL completa del endpoint actual y funciona igual que Astro.request.url para las páginas.
import type { APIRoute } from "astro";
export const GET = (({ params, request }) => { return new Response( JSON.stringify({ path: new URL(request.url).pathname, }), );}) satisfies APIRoute;Endpoints del servidor (rutas de API)
Sección titulada “Endpoints del servidor (rutas de API)”Todo lo descrito en la sección de endpoints de archivos estáticos también se puede usar en modo SSR: los archivos pueden exportar una función GET que recibe un objeto de contexto con propiedades similares al global Astro.
Pero, a diferencia del modo static, cuando habilitas el renderizado bajo demanda para una ruta, el endpoint se construirá cuando sea solicitado. Esto desbloquea nuevas características que no están disponibles en tiempo de construcción, y te permite construir rutas de API que escuchen las peticiones y ejecuten código de forma segura en el servidor en tiempo de ejecución.
Tus rutas se renderizarán bajo demanda de forma predeterminada en modo server. En modo static, debes desactivar el prerrenderizado para cada endpoint personalizado con export const prerender = false.
Asegúrate de habilitar un modo de renderizado bajo demanda antes de probar estos ejemplos, y desactiva el prerrenderizado en modo static.
Los endpoints del servidor pueden acceder a params sin necesidad de exportar getStaticPaths, y pueden devolver un objeto Response, lo que te permite establecer códigos de estado y cabeceras:
import { getProduct } from "../db";
export async function GET({ params }) { const id = params.id; const product = await getProduct(id);
if (!product) { return new Response(null, { status: 404, statusText: "Not found", }); }
return new Response(JSON.stringify(product), { status: 200, headers: { "Content-Type": "application/json", }, });}Esto responderá a cualquier petición que coincida con la ruta dinámica. Por ejemplo, si navegamos a /helmet.json, params.id se establecerá en helmet. Si helmet existe en la base de datos de productos simulada, el endpoint utilizará un objeto Response para responder con JSON y devolver un código de estado HTTP exitoso. Si no, utilizará un objeto Response para responder con un 404.
En modo SSR, ciertos proveedores requieren la cabecera Content-Type para devolver una imagen. En este caso, utiliza un objeto Response para especificar una propiedad headers. Por ejemplo, para producir una imagen binaria .png:
export async function GET({ params, request }) { const response = await fetch( "https://docs.astro.build/assets/full-logo-light.png", ); const buffer = Buffer.from(await response.arrayBuffer());
return new Response(buffer, { headers: { "Content-Type": "image/png" }, });}Métodos HTTP
Sección titulada “Métodos HTTP”Además de la función GET, puedes exportar una función con el nombre de cualquier método HTTP. Cuando llega una petición, Astro comprobará el método y llamará a la función correspondiente.
También puedes exportar una función ALL para que coincida con cualquier método que no tenga una función exportada correspondiente. Si hay una petición sin método coincendente, redirigirá a la página 404 de tu sitio.
export const GET = (({ params, request }) => { return new Response( JSON.stringify({ message: "This was a GET!", }), );}) satisfies APIRoute;
export const POST = (({ request }) => { return new Response( JSON.stringify({ message: "This was a POST!", }), );}) satisfies APIRoute;
export const DELETE = (({ request }) => { return new Response( JSON.stringify({ message: "This was a DELETE!", }), );}) satisfies APIRoute;
export const ALL = (({ request }) => { return new Response( JSON.stringify({ message: `This was a ${request.method}!`, }), );}) satisfies APIRoute;Si defines una función GET pero no una función HEAD, Astro gestionará automáticamente las peticiones HEAD llamando a la función GET y eliminando el cuerpo de la respuesta.
request
Sección titulada “request”En modo SSR, la propiedad request devuelve un objeto Request completamente utilizable que hace referencia a la petición actual. Esto te permite aceptar datos y comprobar cabeceras:
export const POST = (async ({ request }) => { if (request.headers.get("Content-Type") === "application/json") { const body = await request.json(); const name = body.name;
return new Response( JSON.stringify({ message: "Your name was: " + name, }), { status: 200, }, ); }
return new Response(null, { status: 400 });}) satisfies APIRoute;Redirecciones
Sección titulada “Redirecciones”El contexto del endpoint exporta una utilidad redirect() similar a Astro.redirect:
import { getLinkUrl } from "../db";
export async function GET({ params, redirect }) { const { id } = params; const link = await getLinkUrl(id);
if (!link) { return new Response(null, { status: 404, statusText: "Not found", }); }
return redirect(link, 307);}