Remix × Zodix: パラメータやクエリのバリデーションをシンプルに書く
これは何?
Remix でアプリケーションを開発する際、route でのパラメータやクエリのバリデーションは必須です。通常、このバリデーションは手動で行う必要がありますが、zod と zodix というモジュールを使うことでとてもシンプルに書くことができます。
たとえば、URL パラメータのバリデーションと値の取り出しでは以下のように定型句が多く煩雑になりがちですが、zodix はそこで威力を発揮します。
例:
https://remix-app/query?count=100&page=1 のバリデーションを行う方法
zodix がない場合
export async function loader({ request }: LoaderFunctionArgs) {
const { searchParams } = new URL(request.url);
const count = Number(searchParams.get("count"));
const page = Number(searchParams.get("page"));
if(isNaN(count) || isNaN(page)) {
throw new Response("invalid query", { status: 400 })
}
zodix を使う場合
export async function loader({ request }: LoaderFunctionArgs) {
const { count, page } = zx.parseQuery(request, {
count: zx.NumAsString, // 100
page: zx.NumAsString, // 1
});
}
この記事では、zodix の基本的な使い方と、Remix アプリケーションでの活用方法について解説します。
zodix とは
zodix は、Remix の loader や action でパラメータやクエリのバリデーションを簡単に行うための Zod ユーティリティのコレクションです。FormData や URLSearchParams のパースとバリデーションをシンプルにし、loader や action をクリーンで型安全に保ちます。
セットアップ
まず、zodix と zod をインストールします。
pnpm install zodix zod
次に、基本になる zx オブジェクトと、zod のスキーマ定義のための z をインポートします。
import { zx } from "zodix";
import { z } from "zod";
使い方
route パラメータのバリデーション
zx.parseParams を使って、LoaderFunctionArgs['params'] や ActionFunctionArgs['params'] から params オブジェクトをパースしバリデーションできます。
// route: users.$userId.notes.$noteId.tsx
// URL: https://remix-app/users/coji/notes/y8XparQV
export async function loader({ params }: LoaderFunctionArgs) {
const { userId, noteId } = zx.parseParams(params, {
userId: z.string(), // "coji"
noteId: z.string(), // "y8XparQV"
});
}
クエリ文字列 URLSearchParams のバリデーション
zx.parseQuery を使って、Request のクエリ文字列(検索パラメータ)をパースしバリデーションできます。
// URL https://remix-app/users?count=100&page=1
export async function loader({ request }: LoaderFunctionArgs) {
const { count, page } = zx.parseQuery(request, {
count: zx.NumAsString, // 100
page: zx.NumAsString, // 1
});
}
zx.NumAsString は zodix が提供するヘルパー zod スキーマです。詳細は後述します。
フォームデータのバリデーション
zx.parseForm を使って、Remix の action で FormData をパースしバリデーションできます。
export async function action({ request }: ActionFunctionArgs) {
const { email, password, saveSession } = await zx.parseForm(request, {
email: z.string().email(),
password: z.string().min(6),
saveSession: zx.CheckboxAsString,
});
}
ヘルパー Zod スキーマ
FormData と URLSearchParams は全ての値を文字列にシリアライズするため、"5"、"on"、"true" のような値を扱うことがよくあります。zodix には、これらの文字列を適切な型にパースしバリデーションするためのヘルパースキーマが用意されています。
-
zx.BoolAsString: "true" をtrueに、"false" をfalseにパースします。 -
zx.CheckboxAsString: "on" をtrueに、undefinedをfalseにパースします。 -
zx.IntAsString: "3" を3にパースします。小数点以下は切り捨てられます。 -
zx.NumAsString: "3" を3に、"3.14" を3.14にパースします。
これらのヘルパースキーマを使用すると、次のようにフォームデータやクエリ文字列をパースできます。
const Schema = z.object({
isAdmin: zx.BoolAsString,
agreedToTerms: zx.CheckboxAsString,
age: zx.IntAsString,
cost: zx.NumAsString,
});
export async function action({ request }: ActionFunctionArgs) {
const { isAdmin, agreedToTerms, age, cost } = await zx.parseForm(
request,
Schema
);
// isAdmin: boolean
// agreedToTerms: boolean
// age: number
// cost: number
}
export async function loader({ request }: LoaderFunctionArgs) {
const { isAdmin, agreedToTerms, age, cost } = zx.parseQuery(request, Schema);
// isAdmin: boolean
// agreedToTerms: boolean
// age: number
// cost: number
}
この例では、zx.BoolAsString、zx.CheckboxAsString、zx.IntAsString、zx.NumAsString を使用して、フォームデータとクエリ文字列の値を適切な型にパースしています。これにより、action 関数と loader 関数内で、変換された値を型安全に使用できます。
エラーハンドリング
parseParams、parseForm、parseQuery は、パースに失敗した場合に 400 Response をスローします。これは Remix の error boundary とうまく連動し、カスタムエラーハンドリングを必要としない場合に使用するのに適しています。
export async function loader({ params }: LoaderFunctionArgs) {
const { postId } = zx.parseParams(
params,
{ postId: zx.NumAsString },
{ message: "Invalid postId parameter", status: 400 }
);
const post = await getPost(postId);
return { post };
}
export function ErrorBoundary() {
const error = useRouteError();
return (
<div>
<h1>{String(error)}</h1>
</div>
);
}
実際の使用例 (SPA Mode)
zodix は 通常の SSR を行う Remix だけでなく、SPA mode でも使うことができます。
たとえば以下のように、Remix SPA のアプリで実際に使っています。
上記コードを含むリポジトリはこちらです。参考になるとうれしいです。
まとめ
zodix を使うことで、Remix アプリケーションでのパラメータやクエリのバリデーションを簡単に実装できます。zodix は、定義済みの Zod スキーマや独自のスキーマを使用でき、エラーハンドリングも容易です。ぜひ zodix を活用して、Remix アプリケーションの開発を効率化しましょう。
Discussion