mcpField
S
safe-action-validation-errors

safe-action-validation-errors

github.com/next-safe-action開発11.2k 回インストール8 週間前に更新
リポジトリ

safe-action-validation-errors について

next-safe-action のバリデーションエラーを扱うためのリファレンススキルです。自動・手動エラーの形式と、クライアントコードでの表示方法を説明します。

主な機能

  1. 01Schema による自動バリデーションエラー
  2. 02returnValidationErrors() による手動エラー
  3. 03フォーマット済み・フラット化エラー形式
  4. 04フォーム全体・フィールド単位のエラー表示

活用シーン

  1. 01フォームでフィールドエラーを表示
  2. 02フォーム全体の検証失敗を報告
  3. 03サーバー側の検証ルールを処理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/next-safe-action/skills --skill safe-action-validation-errors

インストール後、Claude Code で/safe-action-validation-errorsを入力して読み込まれたか確認します。

同梱ファイルcustom-errors.mderror-shapes.md

詳細

next-safe-action の検証エラー

検証エラーの 2 つの発生源

  1. スキーマ検証 — 入力が .inputSchema() に一致しない場合に自動的に行われます
  2. 手動検証 — サーバーコード内で returnValidationErrors() を使います(例:「メールアドレスはすでに使用されています」)

どちらもクライアントでは同じエラー構造になります。

デフォルトのエラー形式(フォーマット済み)

各階層に _errors 配列がある、スキーマ構造を反映した形式です。

// For schema: z.object({ email: z.string().email(), address: z.object({ city: z.string() }) })
{
  _errors: ["Form-level error"],                    // root errors
  email: { _errors: ["Invalid email address"] },    // field errors
  address: {
    _errors: ["Address section error"],
    city: { _errors: ["City is required"] },        // nested field errors
  },
}

returnValidationErrors

ActionServerValidationError をスローします。フレームワークはこれをキャッチし、result.validationErrors として返します。戻り値を返すことはありません。必ずスローします。

想定される検証以外のエラー(「在庫切れ」「見つかりません」など)には、兄弟ヘルパーの returnServerError(payload) も同じように機能します(内部でスローし、戻り値を返しません)が、result.serverError に型付きペイロードを設定し、handleServerError を経由しません。safe-action-client スキルを参照してください。

"use server";

import { z } from "zod";
import { returnValidationErrors } from "next-safe-action";
import { actionClient } from "@/lib/safe-action";

const registerSchema = z.object({
  email: z.string().email(),
  username: z.string().min(3),
});

export const register = actionClient
  .inputSchema(registerSchema)
  .action(async ({ parsedInput }) => {
    // Check business rules after schema validation passes
    const existingUser = await db.user.findByEmail(parsedInput.email);
    if (existingUser) {
      returnValidationErrors(registerSchema, {
        email: { _errors: ["This email is already registered"] },
      });
    }

    const existingUsername = await db.user.findByUsername(parsedInput.username);
    if (existingUsername) {
      returnValidationErrors(registerSchema, {
        username: { _errors: ["This username is taken"] },
      });
    }

    // Both checks passed — create the user
    const user = await db.user.create(parsedInput);
    return { id: user.id };
  });
ルートレベルのエラー

フォーム全体に関するエラーには、最上位の _errors を使います。

returnValidationErrors(schema, {
  _errors: ["You can only create 5 posts per day"],
});

関連ドキュメント

検証エラーの表示

// Formatted shape (default)
{result.validationErrors?.email?._errors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

// Root-level errors
{result.validationErrors?._errors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}
// Flattened shape
{result.validationErrors?.fieldErrors?.email?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

// Form-level errors (flattened)
{result.validationErrors?.formErrors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

コメント