1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Astro Actionsの投稿設計:FormData・権限・DB移行と二重送信を扱う

1
Last updated at Posted at 2025-11-19

2026-10-12 訂正:現行公式資料ではAstro DBはv6.4で非推奨、v7で削除されています。旧稿の新規導入手順を取り下げ、Actionsの入力検証とDB選定を分けました。FormDataにはaccept: 'form'が必要です。astro:schema、output: 'hybrid'、設定評価時の日時defaultの説明も修正しました。

コメント投稿を、入力・権限・保存・表示へ分ける

Astro Actionsを使って投稿入力を整理する設計例です。API routeを自分で書かなくても、serverへ到達する入口は存在します。関数として呼べることと、認証・認可済みであることは別です。静的HTMLだけのhostでDB書き込みActionが動くとは説明しません。

今回確認したのは公式資料と入力schema、codeの構文です。完成したゲストブックを構築・公開した実績ではありません。

1. Astro DBは旧版の機能として読む

公式Astro DBページとv7移行ガイドはintegrationの削除を説明し、DB機能には別libraryへの移行を勧めています。新規projectへastro add dbする現行手順として使いません。

旧版のdb/config.tsやastro:dbを使うprojectでは、採用版、既存schema、接続先、migration、backupを確認してから移行します。型推論があることだけで、DB制約・並行更新・権限・復元が完成するわけではありません。

Astro Studioの終了案内も参照します。旧稿の「Astro Studioへ簡単に本番deploy」は現在の新規導入先として残しません。必要なDB provider、接続credential、費用、実行環境を別途選びます。

2. FormDataを受けるActionの部分例

現行ActionsガイドのZod importはastro/zodです。入力modeを明示します。以下は投稿前の入力確認だけで、DB保存は行いません。

// src/actions/index.ts
import {defineAction, ActionError} from 'astro:actions'
import {z} from 'astro/zod'

export const server = {
  prepareComment: defineAction({
    accept: 'form',
    input: z.object({author: z.string().trim().min(1).max(20), body: z.string().trim().min(1).max(140)}),
    handler: async (input, context) => {
      if (!context.locals.user) {
        throw new ActionError({code: 'UNAUTHORIZED'})
      }
      return {author: input.author, body: input.body}
    },
  }),
}

locals.userはアプリ側がsessionを検証して設定する前提です。Astroが自動でログインを作るわけではありません。App.Localsの型、middleware、session失効を実装・検証する必要があります。Cookieの存在だけを本人確認にしません。

空白だけのauthor/bodyもtrim後に拒否します。上限の文字数はJavaScriptの文字列長の規則で、人が見た一文字と必ず同じではありません。HTML等の本文は表示時にescapeし、入力された文字列をそのままHTMLへ挿入しません。

3. フロントは成功と結果不明を分ける

Reactフォーム等からnew FormData(form)を渡す場合、Action側もform modeへそろえます。defaultのJSON入力にFormDataを送る旧稿の組み合わせは修正が必要です。

フォームではlabelのhtmlForとinputのidを結び、必須・上限、pending、error、成功通知を用意します。複数フォームがある場合はIDの衝突を避けます。画面のdisabledは操作上の重複を減らすもので、serverでの二重投稿防止ではありません。

入力確認Actionの戻り値を「投稿しました」と表示しません。書き込みActionを追加した後も、通信失敗は書き込み失敗確定とは限らないため、内容を消さず結果確認の導線を残します。reloadだけで成功メッセージが消える設計も避けます。

4. 保存するActionに必要な条件

保存では、投稿可能な利用者・対象の認可、rate limit、spam・moderation、本文サイズ、処理状態、二重投稿防止を確認します。署名済みsession等の認証情報と、フォームから来た表示名は別です。クライアントの利用者IDをそのまま権限判断に使いません。

受付IDと利用者の組み合わせへDB制約を置く等、同時実行にも対応する規則を設計します。同じIDで内容が違う再送は無条件に成功扱いにしません。DB commit後に応答が失われた場合、同じ受付から既存結果を照合します。ここではそのDB実装は掲載していません。

旧稿のcolumn.date({default: new Date()})は設定評価時の値で、各投稿時の現在時刻を生成する関数ではありません。採用DBの適切なserver-side default、またはinsert時のserver時刻を使い、timezoneとclockの方針を決めます。新しい投稿日時をクライアントに自由に指定させません。

5. 動的配信・取得上限・復旧を確認する

v5移行ガイドではoutput: 'hybrid'が削除されています。採用版に合わせ、対応adapterとoutput: 'server'、または対象routeのprerender = false等を選びます。設定名だけでDB接続・Action・最新一覧の配信が完成するわけではありません。

一覧は全件無制限取得を避け、上限とpagingを設計します。日時だけの並びは同時刻の順序が不定になり得るため、ID等の安定した条件も考えます。投稿成功、一覧再取得、配信cacheを別に確認します。

正常入力、空白、不正型、上限超過、未認証・認可外、rate limit、同時再送、commit結果不明、DB停止、削除、復元を確認します。今回ローカルで確認したのは合成入力のschema判定とTS構文です。Astro型・実行、session、DB、フォーム、adapter、配信・復旧は未検証です。

この記事を書いた人✏️@YushiYamamoto
ITPRODX.com代表 / AIアーキテクト
Next.js / TypeScript / n8nを活用した自律型アーキテクチャ設計を専門としています。
日々の自動化の検証結果や、ビジネス側の視点(ROI等)に関するより深い考察は、以下の公式サイトおよびnoteで発信しています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?