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.
Importaciones desde astro:actions
Sección titulada «Importaciones desde astro:actions»import { actions, defineAction, isInputError, isActionError, ActionError, } from 'astro:actions';
defineAction()
Sección titulada «defineAction()»
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.
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}!` } })}
Propiedad handler()
Sección titulada «Propiedad handler()»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()
.
Validador del input
Sección titulada «Validador del input»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.
Uso con accept: 'form'
Sección titulada «Uso con accept: 'form'»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 conz.number()
- Entradas tipo
checkbox
conz.coerce.boolean()
- Entradas tipo
file
conz.instanceof(File)
- Múltiples entradas con el mismo
name
pueden validarse conz.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 } } }, }),};
isInputError()
Sección titulada «isInputError()»Tipo: (error?: unknown | ActionError) => boolean
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.
isInputError()
.
isActionError()
Sección titulada «isActionError()»Tipo: (error?: unknown | ActionError) => boolean
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
.
ActionError
Sección titulada «ActionError»
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 validadorinput
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 encabezadoContent-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.
message
Sección titulada «message»
Agregado en:
astro@4.15.0
La propiedad message
acepta una cadena de texto. (por ejemplo: “El usuario debe iniciar sesión.“)
getActionContext()
Sección titulada «getActionContext()»Tipo: (context: APIContext) => ActionMiddlewareContext
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.
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.
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 } // ...});
setActionResult()
Sección titulada «setActionResult()»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.
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();});
serializeActionResult()
Sección titulada «serializeActionResult()»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()
:
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)); } // ...});
deserializeActionResult()
Sección titulada «deserializeActionResult()»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.
getActionPath()
Sección titulada «getActionPath()»Tipo: (action: ActionClient<any, any, any>) => string
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
:
<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
:
<script>import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon( getActionPath(actions.like), new Blob([JSON.stringify({ id: 'YOUR_ID' })], { type: 'application/json' }))</script>