Actions и формы
Actions (действия) — серверные функции, которые можно вызвать из браузера как обычную функцию JavaScript. Astro сам создаёт для них адрес, проверяет входные данные по схеме zod и возвращает результат или ошибку. Это удобнее, чем писать эндпоинт и разбирать запрос вручную. Действиям нужен адаптер сервера из урока о рендеринге по запросу.
Описание действия
Все действия объявляют в файле src/actions/index.ts. Создайте его:
// src/actions/index.ts
import { defineAction } from 'astro:actions';
import { z } from 'astro:schema';
const comments: { postId: string; author: string; text: string }[] = [];
export const server = {
addComment: defineAction({
accept: 'form',
input: z.object({
postId: z.string(),
author: z.string().min(2),
text: z.string().min(1).max(500),
}),
handler: async (input) => {
comments.push(input);
return { total: comments.length };
},
}),
};accept: 'form' говорит, что данные придут из HTML-формы. input — схема: имя не короче двух символов, текст от 1 до 500. handler получает уже проверенные данные. Комментарии здесь хранятся в памяти сервера, в настоящем блоге их сохраняют в базу данных.
Форма на странице статьи
Добавьте форму в src/pages/posts/[id].astro после текста статьи:
<form id="comment-form">
<input type="hidden" name="postId" value={post.id} />
<input name="author" placeholder="Ваше имя" />
<textarea name="text" placeholder="Комментарий"></textarea>
<button>Отправить</button>
</form>
<p id="comment-status"></p>
<script>
import { actions, isInputError } from 'astro:actions';
const form = document.querySelector('#comment-form') as HTMLFormElement;
const status = document.querySelector('#comment-status') as HTMLElement;
form.addEventListener('submit', async (event) => {
event.preventDefault();
const { data, error } = await actions.addComment(new FormData(form));
if (isInputError(error)) {
status.textContent = error.fields.author?.join(', ') ?? 'Проверьте поля формы';
} else if (error) {
status.textContent = 'Не удалось отправить комментарий';
} else {
status.textContent = `Спасибо! Комментариев: ${data.total}`;
form.reset();
}
});
</script>Откройте статью, введите имя «Олег» и текст, нажмите «Отправить» — под формой появится «Спасибо! Комментариев: 1». С именем из одной буквы появится сообщение об ошибке поля author.
Результат вызова
| Поле | Что в нём |
|---|---|
data | То, что вернул handler, если всё прошло успешно |
error | Ошибка: неверные данные или сбой в handler |
error.fields | Для ошибок проверки — сообщения по каждому полю |
Чтобы сообщить об ошибке самому, handler выбрасывает ActionError из astro:actions с кодом, например NOT_FOUND.
Форма без JavaScript
Форму можно отправить и без скрипта: атрибут action={actions.addComment} и method="POST" у тега <form>. Тогда страница должна формироваться по запросу (export const prerender = false), а результат читают через Astro.getActionResult(actions.addComment).
Частая ошибка
Проверяют данные только в браузере — атрибутами required и minlength — и пропускают схему input. Запрос к действию можно отправить в обход формы, и в базу попадёт что угодно. Проверка в input выполняется на сервере, поэтому описывайте в ней все требования к данным.