前置き
突然ですが、Next.jsのServer Actionsって便利ですよね?皆さん使っていますか?
ただ、もっとこんなことができたらいいのになぁって思う瞬間があるかもしれません。例えば、
- エラーハンドリングを共通化したい
- 認可処理を共通化したい
- 上記をやりつつ型安全を維持したい
と思ったことはありませんか?
そんな時は、next-safe-action
を使用すれば全て解決するかもしれません。
next-safe-actionとは
next-safe-action
は、Next.jsのServer Actionsをラップし、安全に扱えるようにするライブラリです。
公式ドキュメント:next-safe-action
主な特徴は以下の通りです。
- 型安全なServer Actionsの作成
- 一元的なエラーハンドリング
- Middlewareによる共通処理の適用
使い方
インストール
まずは、next-safe-action
をインストールします。
ついでに、client側のformライブラリ(react-hook-form)とvalidation libraryをインストールします。
npm install next-safe-action zod react-hook-form @hookform/resolvers
createSafeActionの使い方
createSafeAction
を使用すると、型安全なServer Actionを簡単に作成できます。
'use server';
import { createSafeAction } from 'next-safe-action';
import { z } from 'zod';
const action = createSafeActionClient({
// エラーハンドリング処理
handleServerError(e, utils) {
// You can access these properties inside the `utils` object.
const { clientInput, bindArgsClientInputs, metadata, ctx } = utils;
// Log to console.
console.error("Action error:", e.message);
// 共通的なエラー処理
return "エラーが発生しました";
},
});
export const sampleSchema = z.object({
name: z.string(),
});
export const sampleAction = action
.schema(sampleSchema)
.action(async ({ input }) => {
return `Hello ${input.name}`
});
export default action;
このようにcreateSafeAction
を使うことで、共通的なactionを定義することができます。
ここでは、「共通的なエラーハンドリング」が実現できます。
さらに、各actionではshcemaを指定することで、簡単に型を指定することができます。
Middlewareの活用
Middlewareを利用することで、認可処理やロギングを共通化できます。
import { createSafeAction } from 'next-safe-action';
import { z } from 'zod';
const action = createSafeActionClient({
// エラーハンドリング処理
handleServerError(e, utils) {
// You can access these properties inside the `utils` object.
const { clientInput, bindArgsClientInputs, metadata, ctx } = utils;
// Log to console.
console.error("Action error:", e.message);
// 共通的なエラー処理
return "エラーが発生しました";
},
}).use(async ({ next }) => {
const session = cookies().get("session")?.value;
if (!session) {
throw new Error("Session not found!");
}
const userId = await getUserIdFromSessionId(session);
if (!userId) {
throw new Error("Session is not valid!");
}
// Return the next middleware with `userId` value in the context
return next({ ctx: { userId } });
});;
actionの定義の後に.use
と繋げることで共通的なロギング処理や認可処理も定義することが可能です!
Client側の実装
Client側では、react-hook-form
とzod
を組み合わせてフォームを作成し、next-safe-action
を活用できます。
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useAction } from "next-safe-action/hooks";
import { z } from 'zod';
import { sampleAction, sampleSchema } from '../actions';
import { useState } from 'react';
type FormData = z.infer<typeof sampleSchema>;
export default function Form() {
// useActionで簡単にaction処理を呼び出せます!
const { execute } = useAction(sampleAction);
const { control, handleSubmit } = useForm<FormData>({
defaultValues: {
name: "John",
},
resolver: zodResolver(sampleSchema),
});
return (
<form onSubmit={handleSubmit(execute)}>
<div>
<label>名前:</label>
<input {...register('name')} />
</div>
<button type="submit">送信</button>
{response && <p>サーバーからの応答: {response}</p>}
</form>
);
}
このフォームでは、
-
react-hook-form
でフォーム管理 -
zod
で入力バリデーション -
next-safe-action
で型安全なServer Actionの呼び出し
を実現しています。
clinet側ではuseAction
が超絶便利!
https://next-safe-action.dev/docs/execute-actions/hooks/useaction
処理だけではなく、statusなども取得できるし、callback系の処理を引数に指定できるので成功時の処理などを簡単にわかりやすく指定できます!
まとめ
Next.jsのServer Actionsをより安全に使うためには、next-safe-action
が非常に便利です。
-
createSafeAction
で型安全・エラーハンドリングを強化 -
middleware
で認可処理を共通化 -
react-hook-form
とzod
でClient側のフォームを型安全に実装
この記事では伝えていない機能もたくさんあるので是非みなさん使ってみてください!