Astro กับ Hono: สร้าง Full-stack App บน Cloudflare Workers

#astro13 เม.ย. 2569

ทำไมต้อง Astro + Hono

Astro ดีสำหรับ frontend แต่ถ้าต้องการ API ที่ซับซ้อน Hono เป็นตัวเลือกที่ดีมาก ทั้งคู่ทำงานบน Cloudflare Workers ได้ดีเยี่ยม

ติดตั้ง

npx astro add cloudflare
npm install hono

ตั้งค่า Astro

// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server',
  adapter: cloudflare()
});

สร้าง Hono API

// src/pages/api/[...path].ts
import { Hono } from 'hono';
import type { APIRoute } from 'astro';

const app = new Hono().basePath('/api');

app.get('/users', async (c) => {
  const db = c.env.DB;
  const users = await db.prepare('SELECT * FROM users').all();
  return c.json(users.results);
});

app.post('/users', async (c) => {
  const body = await c.req.json();
  const db = c.env.DB;
  await db.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
    .bind(body.name, body.email)
    .run();
  return c.json({ success: true }, 201);
});

export const ALL: APIRoute = ({ request, locals }) => {
  return app.fetch(request, locals.runtime.env);
};

ใช้ API จาก Astro Page

---
// src/pages/users.astro
const response = await fetch('/api/users');
const users = await response.json();
---

<ul>
  {users.map((user: any) => (
    <li>{user.name} - {user.email}</li>
  ))}
</ul>

Middleware ร่วมกัน

app.use('*', async (c, next) => {
  const token = c.req.header('Authorization');
  if (!token) return c.json({ error: 'Unauthorized' }, 401);
  await next();
});

D1 Database

// wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxx"
app.get('/posts', async (c) => {
  const { results } = await c.env.DB
    .prepare('SELECT * FROM posts ORDER BY created_at DESC')
    .all();
  return c.json(results);
});

สรุป

Astro + Hono บน Cloudflare Workers เป็น stack ที่ทรงพลังมาก ได้ทั้ง static site performance และ full API capability ในราคาถูกมากครับ