Astro Actions: Type-safe Server Functions
#astro13 เม.ย. 2569
Astro Actions คืออะไร
Astro Actions (Astro 4.15+) เป็น type-safe server functions ที่เรียกจาก client ได้โดยตรง คล้ายกับ Server Actions ใน Next.js
สร้าง Actions
// src/actions/index.ts
import { defineAction, z } from 'astro:actions';
export const server = {
createPost: defineAction({
input: z.object({
title: z.string().min(1),
content: z.string().min(10),
tags: z.array(z.string())
}),
handler: async (input, context) => {
const user = context.locals.user;
if (!user) throw new ActionError({ code: 'UNAUTHORIZED' });
const post = await db.insert(posts).values({
...input,
authorId: user.id,
createdAt: new Date()
}).returning();
return { post: post[0] };
}
}),
deletePost: defineAction({
input: z.object({ id: z.number() }),
handler: async ({ id }, context) => {
await db.delete(posts).where(eq(posts.id, id));
return { success: true };
}
})
};
เรียกใช้จาก Client
---
import { actions } from 'astro:actions';
---
<form method="POST" action={actions.createPost}>
<input name="title" />
<textarea name="content"></textarea>
<button type="submit">สร้างบทความ</button>
</form>
เรียกใช้ด้วย JavaScript
import { actions } from 'astro:actions';
async function handleSubmit(formData: FormData) {
const { data, error } = await actions.createPost({
title: formData.get('title') as string,
content: formData.get('content') as string,
tags: ['astro']
});
if (error) {
console.error(error.message);
return;
}
console.log('สร้างสำเร็จ:', data.post);
}
Error Handling
import { ActionError } from 'astro:actions';
handler: async (input) => {
const existing = await db.query.posts.findFirst({
where: eq(posts.title, input.title)
});
if (existing) {
throw new ActionError({
code: 'CONFLICT',
message: 'มีบทความชื่อนี้แล้ว'
});
}
}
สรุป
Astro Actions ทำให้เขียน server logic ได้ง่ายและ type-safe โดยไม่ต้องสร้าง API endpoint แยกต่างหาก เหมาะกับ form submissions และ mutations ครับ