Actions
ปัญหาที่ Actions แก้
หัวข้อที่มีชื่อว่า “ปัญหาที่ Actions แก้”การจะเรียก server logic จาก client แบบเดิม คุณต้องเขียน endpoint, คิด URL, fetch() เอง, stringify body, เดา type ของ response และ validate input ด้วยมือบน server Actions ยุบทั้งหมดนั้นเหลือ function ที่ typed ตัวเดียว: define บน server แล้วเรียกจาก client ด้วย type-safety เต็มและ validation อัตโนมัติ
define action
หัวข้อที่มีชื่อว่า “define action”Action อยู่ใน src/actions/index.ts export เป็น object ชื่อ server แต่ละตัวคือ defineAction ที่มี schema input (Zod) และ handler:
import { defineAction } from 'astro:actions';import { z } from 'astro/zod';
export const server = { createComment: defineAction({ input: z.object({ postId: z.string(), body: z.string().min(1).max(2000), }), handler: async (input, context) => { // input is fully typed and already validated against the schema. const comment = await db.comments.create({ postId: input.postId, body: input.body, userId: context.locals.user?.id, // per-request data from middleware }); return comment; // the return type flows to the client }, }),};สองอย่างเป็นอัตโนมัติ: input ถูก validate กับ Zod schema ก่อน handler รัน และ return type ของ handler ถูก infer ไปจนถึงผู้เรียก — ไม่ต้อง type response ด้วยมือ
เรียก action จาก client
หัวข้อที่มีชื่อว่า “เรียก action จาก client”ฝั่ง client ให้ import actions จาก astro:actions แล้วเรียกใช้ ทุกการเรียก return { data, error } — Astro ไม่ throw ข้าม boundary:
import { actions, isInputError } from 'astro:actions';
const { data, error } = await actions.createComment({ postId: '42', body: 'Nice post!',});
if (isInputError(error)) { // Validation failed — error.fields has per-field messages. console.log(error.fields.body);} else if (data) { console.log('Created comment', data.id); // data is typed}sequenceDiagram
participant C as Client
participant A as Astro Action
participant H as handler
C->>A: actions.createComment(input)
A->>A: validate input against Zod schema
A->>H: run handler(input, context)
H-->>A: return value (typed)
A-->>C: { data, error } form และ progressive enhancement
หัวข้อที่มีชื่อว่า “form และ progressive enhancement”Action เชื่อมกับ HTML <form> ตรง ๆ ได้ด้วยการส่ง action.name — ทำงานเป็น form POST ปกติแม้ JavaScript ยังไม่โหลด แล้วอัปเกรดเป็น client call เมื่อ hydrate นี่คือ progressive enhancement: form submit ได้ทั้งสองทาง
---import { actions } from 'astro:actions';---<form method="POST" action={actions.createComment}> <input type="hidden" name="postId" value="42" /> <textarea name="body"></textarea> <button type="submit">Comment</button></form>คุณยังเรียก action จาก component script ได้ด้วย Astro.callAction(actions.createComment, input) เมื่อต้องการผลตอน server render handler ที่ validate แล้วตัวเดียวกันจะรันในทุกกรณี