Saltearse al contenido

Referencia de la API de Acciones

Agregado en: astro@4.15.0

Las Acciones te ayudan a construir un backend con tipado seguro que puedes llamar desde código cliente y formularios HTML. Todas las utilidades para definir y llamar a las acciones están disponibles en el módulo astro:actions. Para ejemplos e instrucciones de uso, consulta la guía de Acciones.

import {
actions,
defineAction,
isInputError,
isActionError,
ActionError,
} from 'astro:actions';

Agregado en: astro@4.15.0

La utilidad defineAction() se usa para definir nuevas acciones desde el archivo src/actions/index.ts. Acepta una función handler() que contiene la lógica del servidor a ejecutar, y una propiedad opcional input para validar los parámetros de entrada en tiempo de ejecución.

src/actions/index.ts
import { defineAction } from 'astro:actions';
import { z } from 'astro:schema';
export const server = {
getGreeting: defineAction({
input: z.object({
name: z.string(),
}),
handler: async (input, context) => {
return `Hola, ${input.name}!`
}
})
}

Tipo: (input, context) => any

defineAction() requiere una función handler() que contenga la lógica del servidor a ejecutar cuando se llama a la acción. Los datos devueltos por el handler se serializan automáticamente y se envían al llamador.

El handler() recibe como primer argumento la entrada del usuario. Si se establece un validador input, la entrada del usuario se validará antes de ser pasada al handler. El segundo argumento es un objeto context que contiene la mayoría del contexto estándar de los endpoints de Astro (/es/reference/api-reference/), excluyendo getActionResult(), callAction() y redirect().

Los valores devueltos se procesan usando la biblioteca devalue. Esto soporta valores JSON y las instancias de Date(), Map(), Set() y URL().

Tipo: ZodType | undefined

La propiedad opcional input acepta un validador Zod (por ejemplo, un objeto Zod o una unión discriminada Zod) para validar las entradas del handler en tiempo de ejecución. Si la acción no pasa la validación, se devuelve un error BAD_REQUEST y el handler no se ejecuta.

Si se omite input, el handler recibirá una entrada de tipo unknown para solicitudes JSON y tipo FormData para solicitudes de formulario.

Si tu acción acepta entradas de formulario, usa el validador z.object() para parsear automáticamente los datos del formulario a un objeto tipado. Todos los validadores Zod son compatibles con campos de datos de formulario (por ejemplo, z.coerce.date()). Astro provee manejo especial interno para validar cómodamente los siguientes tipos de entradas:

  • Entradas de tipo number pueden validarse con z.number()
  • Entradas tipo checkbox con z.coerce.boolean()
  • Entradas tipo file con z.instanceof(File)
  • Múltiples entradas con el mismo name pueden validarse con z.array(/* validador */)
  • Todas las demás entradas pueden validarse con z.string()

Funciones de extensión como .refine(), .transform() y .pipe() también son compatibles en el validador z.object().

Para aplicar una unión de diferentes validadores, usa el wrapper z.discriminatedUnion() para delimitar el tipo basado en un campo específico del formulario. Este ejemplo acepta una sumisión de formulario para “crear” o “actualizar” un usuario, usando el campo del formulario llamado type para determinar contra qué objeto validar:

import { defineAction } from 'astro:actions';
import { z } from 'astro:schema';
export const server = {
changeUser: defineAction({
accept: 'form',
input: z.discriminatedUnion('type', [
z.object({
// Coincide cuando el campo `type` tiene el valor `create`
type: z.literal('create'),
name: z.string(),
email: z.string().email(),
}),
z.object({
// Coincide cuando el campo `type` tiene el valor `update`
type: z.literal('update'),
id: z.number(),
name: z.string(),
email: z.string().email(),
}),
]),
async handler(input) {
if (input.type === 'create') {
// entrada es { type: 'create', name: string, email: string }
} else {
// entrada es { type: 'update', id: number, name: string, email: string }
}
},
}),
};

Tipo: (error?: unknown | ActionError) => boolean

Agregado en: astro@4.15.0

La utilidad isInputError() se usa para verificar si un ActionError es un error de validación de entrada. Cuando el validador input es un z.object(), los errores de entrada incluyen un objeto fields con mensajes de error agrupados por nombre.

Consulta la guía de errores de entrada en formularios para más información sobre cómo usar isInputError().

Tipo: (error?: unknown | ActionError) => boolean

Agregado en: astro@4.15.0

La utilidad isActionError() se usa para verificar si tu acción lanzó un ActionError dentro de la propiedad handler. Esto es útil para precisar el tipo de un error genérico dentro de un bloque try / catch.

Agregado en: astro@4.15.0

El constructor ActionError() se utiliza para crear errores que son lanzados por el handler de una acción. Este acepta una propiedad code que describe el error ocurrido (por ejemplo: "UNAUTHORIZED"), y una propiedad opcional message con detalles adicionales.

Agregado en: astro@4.15.0

La propiedad code acepta versiones legibles para humanos de todos los códigos de estado HTTP. Los siguientes códigos son compatibles:

  • BAD_REQUEST (400): El cliente envió datos inválidos. Este error se lanza cuando el validador input de una acción no valida correctamente.
  • UNAUTHORIZED (401): El cliente carece de credenciales de autenticación válidas.
  • FORBIDDEN (403): El cliente no está autorizado para acceder a un recurso.
  • NOT_FOUND (404): El servidor no puede encontrar el recurso solicitado.
  • METHOD_NOT_SUPPORTED (405): El servidor no soporta el método solicitado.
  • TIMEOUT (408): El servidor agotó el tiempo mientras procesaba la solicitud.
  • CONFLICT (409): El servidor no puede actualizar un recurso debido a un conflicto.
  • PRECONDITION_FAILED (412): El servidor no cumple una precondición de la solicitud.
  • PAYLOAD_TOO_LARGE (413): El servidor no puede procesar la solicitud porque la carga es demasiado grande.
  • UNSUPPORTED_MEDIA_TYPE (415): El servidor no soporta el tipo de medio de la solicitud. Nota: Las acciones ya verifican el encabezado Content-Type para solicitudes JSON y de formularios, por lo que probablemente no necesites usar este código manualmente.
  • UNPROCESSABLE_CONTENT (422): El servidor no puede procesar la solicitud debido a errores semánticos.
  • TOO_MANY_REQUESTS (429): El servidor ha excedido un límite de tasa especificado.
  • CLIENT_CLOSED_REQUEST (499): El cliente cerró la solicitud antes de que el servidor pudiera responder.
  • INTERNAL_SERVER_ERROR (500): El servidor falló inesperadamente.
  • NOT_IMPLEMENTED (501): El servidor no soporta la característica solicitada.
  • BAD_GATEWAY (502): El servidor recibió una respuesta inválida de un servidor upstream.
  • SERVICE_UNAVAILABLE (503): El servidor está temporalmente no disponible.
  • GATEWAY_TIMEOUT (504): El servidor recibió un tiempo de espera de un servidor upstream.

Agregado en: astro@4.15.0

La propiedad message acepta una cadena de texto. (por ejemplo: “El usuario debe iniciar sesión.“)

Tipo: (context: APIContext) => ActionMiddlewareContext

Agregado en: astro@5.0.0

getActionContext() es una función que se llama desde el manejador de tu middleware para obtener información sobre las solicitudes de acciones entrantes.

Esta función devuelve un objeto action con información sobre la solicitud, además de las funciones setActionResult() y serializeActionResult() para establecer programáticamente el valor que retorna Astro.getActionResult().

getActionContext() te permite obtener y establecer resultados de acciones de forma programática usando middleware, lo que facilita persistir resultados de acciones provenientes de formularios HTML, restringir solicitudes de acciones con verificaciones de seguridad adicionales, y más.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
return next();
});

Tipo: { calledFrom: 'rpc' | 'form', name: string, handler: () => Promise<SafeResult<any, any>> } | undefined

action es un objeto que contiene información sobre una solicitud de acción entrante.

Está disponible a través de getActionContext(), y proporciona el nombre de la acción, el manejador, y si la acción fue llamada desde una función RPC del lado cliente (por ejemplo, actions.newsletter()) o desde una acción de formulario HTML.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'rpc' && action.name.startsWith('private')) {
// Comprobar que el token de sesión sea válido
}
// ...
});

Tipo: (actionName: string, actionResult: SerializedActionResult) => void

setActionResult() es una función para establecer programáticamente el valor que retorna Astro.getActionResult() en middleware. Se le pasa el nombre de la acción y un resultado de acción serializado mediante serializeActionResult().

Esto es útil cuando se llaman las acciones desde un formulario HTML para persistir y cargar resultados desde una sesión.

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
// ... manejar el resultado de la acción
setActionResult(action.name, serializeActionResult(result));
}
return next();
});
Mira la guía avanzada de sesiones para ver una implementación de ejemplo usando Netlify Blob.

Tipo: (result: SafeResult<any, any>) => SerializedActionResult

serializeActionResult() serializa el resultado de una acción a JSON para su persistencia. Esto es necesario para manejar correctamente valores de retorno que no son JSON, como Map o Date, así como el objeto ActionError.

Llama a esta función al serializar un resultado de acción para pasarlo a setActionResult():

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action) {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
// ...
});

Tipo: (result: SerializedActionResult) => SafeResult<any, any>

deserializeActionResult() revierte el efecto de serializeActionResult() y devuelve un resultado de acción a su estado original. Esto es útil para acceder a los objetos data y error en un resultado de acción serializado.

Tipo: (action: ActionClient<any, any, any>) => string

Agregado en: astro@5.1.0

La utilidad getActionPath() acepta una acción y devuelve una ruta URL para que puedas ejecutar una llamada a la acción usando fetch() directamente. Esto te permite proporcionar detalles como encabezados personalizados cuando llamas a tu acción. Luego, puedes manejar los datos devueltos con formato personalizado según sea necesario, como si hubieras llamado a la acción directamente.

Este ejemplo muestra cómo llamar a una acción definida como like pasando el encabezado Authorization y la opción keepalive:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
await fetch(getActionPath(actions.like), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({ id: 'YOUR_ID' }),
keepalive: true
})
</script>

Este ejemplo muestra cómo llamar a la misma acción like utilizando la API sendBeacon:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon(
getActionPath(actions.like),
new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
type: 'application/json'
})
)
</script>
Contribuir Comunidad Patrocinador