🔺

zod-prisma-typesを活用して型安全なアプリケーションを構築する

2024/02/14に公開

はじめまして、ikechan こといけがわです。

今回は業務でtypescriptを使用したプロジェクトで活用しているzod-prisma-typesの基本的な使い方から設定オプションについて順に解説していきます。

目次

  1. 概要
  2. インストール
  3. Prisma Schemaの設計
  4. バリデーションルール
  5. generator zodオプションの紹介
  6. 実際の使用例
  7. まとめ

1. 概要

zod-prisma-typesはPrismaスキーマからZodバリデーションスキーマを自動生成し、型安全な開発を助けるライブラリです。

https://www.npmjs.com/package/zod-prisma-types#createpartialtypes
https://github.com/chrishoermann/zod-prisma-types

2. インストール

npm install zod-prisma-types
# または
yarn add zod-prisma-types
# または
pnpm add zod-prisma-types

3. Prisma Schemaの設計

generator zod {
  provider                         = "zod-prisma-types"
    output                           = "./generated/zod" // 出力ディレクトリの指定
  useMultipleFiles                 = true // スキーマを複数ファイルに分割
  writeBarrelFiles                 = false // バレルファイルの生成を無効化
  createInputTypes                 = false // 入力タイプの生成を無効化
  createModelTypes                 = true // モデルタイプの生成を有効化
  addInputTypeValidation           = true // 入力タイプに対するバリデーションの追加
  createOptionalDefaultValuesTypes = true // デフォルト値を持つフィールドをオプショナルに
  createRelationValuesTypes        = true // リレーションフィールドを含むタイプの生成
  createPartialTypes               = true // 全フィールドをオプショナルにしたパーシャルタイプの生成
  useDefaultValidators             = false // Zodのデフォルトバリデータの使用を無効化
}

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(uuid())
  /// @zod.string.max(30, { message: "Please enter less than 30 characters" })
  name      String
  /// @zod.string.email().max(255, { message: "255字未満で入力してください" })
  email     String
  password  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  address   Address?
}

model Address {
  id            String   @id @default(uuid())
  userId        String   @unique
  name          String
  kana          String
  phone         String
  country       Country
  prefecture    String
  cityAndStreet String
  building      String
  postalCode    String
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt
  user          User     @relation(fields: [userId], references: [id])
}

enum Country {
  jp
  us
  cn
  it
  ch
}

5. generator zodオプションの詳細

  • *zod-prisma-types*の設定オプションを活用することで、生成されるスキーマのカスタマイズが可能です。以下に、主なオプションとその使用方法を示します。
generator zod {
  provider                         = "zod-prisma-types"
  output                           = "./generated/zod" // default is ./generated/zod
  useMultipleFiles                 = false // default is false
  writeBarrelFiles                 = true // default is true
  createInputTypes                 = false // default is true
  createModelTypes                 = true // default is true
  addInputTypeValidation           = true // default is true
  addIncludeType                   = true // default is true
  addSelectType                    = true // default is true
  validateWhereUniqueInput         = true // default is true
  createOptionalDefaultValuesTypes = false // default is false
  createRelationValuesTypes        = false // default is false
  createPartialTypes               = false // default is false
  useDefaultValidators             = true // default is true
  coerceDate                       = true // default is true
  writeNullishInModelTypes         = false // default is false
  prismaClientPath                 = "./path/to/prisma/client" // default is client output path
}

  • provider 使用するジェネレーターを指定します。"zod-prisma-types"が標準の設定値です。
  • output 生成されるZodスキーマファイルが保存されるディレクトリのパス。
    例: "./generated/zod"。
  • useMultipleFiles trueに設定すると、各Prismaモデルに対応するZodスキーマが個別のファイルとして生成されます。
  • writeBarrelFiles falseに設定すると、各ディレクトリのバレルファイル(一括エクスポート用のインデックスファイル)の生成がスキップされます。
  • createInputTypes falseに設定すると、Prismaの入力タイプに相当するZodスキーマの生成が行われません。
  • createModelTypes trueに設定すると、Prismaモデルに基づいたZodスキーマの生成が行われます。
  • addInputTypeValidation trueに設定すると、入力タイプスキーマにカスタムバリデーションルールが追加されます。
  • createOptionalDefaultValuesTypes trueに設定すると、デフォルト値を持つフィールドがオプショナルとして扱われるZodスキーマが生成されます。
  • createRelationValuesTypes trueに設定すると、リレーションを持つモデルのためのZodスキーマが生成され、リレーションフィールドを含むタイプが追加されます。
  • createPartialTypes trueに設定すると、モデルの全フィールドをオプショナルにした「パーシャル」タイプのZodスキーマが生成されます。
  • useDefaultValidators falseに設定すると、Zodによるデフォルトのバリデーション(例: 文字列長のチェック)が適用されなくなります。

6. バリデーションルールの強化

オプションが沢山ありますが、ここではcreateModelTypesにフォーカスを当てて説明したいと思います。createModelTypesはデフォルトでtrueで設定されている為、特に指定しなくても使用できます。

以下の様にPrismaモデルにコメントを追加することで、Zodバリデーションルールを簡単に追加できます。

model User {
  id        String   @id @default(uuid())
  /// @zod.string.max(30, { message: "Please enter less than 30 characters" })
  name      String
  /// @zod.string.email().max(255, { message: "255字未満で入力してください" })
}

エラーメッセージに設定する言語は英語だけでなく日本語も対応しています。

export const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().max(30, { message: "Please enter less than 30 characters" }),
  email: z.string().email().max(255, { message: "255字未満で入力してください" }),
  password: z.string(),
  createdAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
})

7. 実際の簡単な使用例

豊富なオプションがありますが、最近のプロジェクトでは最低限のファイルを生成するようにcreateInputTypes = falseとしています。

generator zod {
  provider         = "zod-prisma-types"
  createInputTypes = false
}

APIリクエストをバリデートする際に、生成されたZodスキーマUserSchemaを以下のように使用します。

import { Hono } from 'hono';
import { PrismaClient } from '@prisma/client';
import { UserSchema, AddressSchema } from './generated/zod';

const app = new Hono();
const prisma = new PrismaClient();
// ユーザー登録エンドポイント
app.post('/register/user', async (c) => {
  try {
    // リクエストボディのバリデーション
    const userData = UserSchema.parse(c.req.body);
    
    // バリデーションが成功したら、Prismaクライアントを使ってデータベースにユーザーを登録
    const user = await prisma.user.create({
      data: userData,
    });

    return c.json(user, 201);
  } catch (error) {
    // バリデーションエラーの場合
    return c.json({ message: error.message }, 400);
  }
});

8. まとめ

今回はtypescriptを利用しているプロジェクトでzod-prisma-typesを利用する方法について紹介しました。
現在のプロジェクトではオプションの多くを活用していない状況ですが、徐々に上手く活用できるようにしていきたいです!
型安全性を高めながら開発プロセスの生産性を向上させるための強力なツールですので、ご興味持たれた方は一度利用してみてください!

最後に、toraco株式会社ではエンジニアを積極採用中です。
フロントエンドエンジニア、バックエンドエンジニア、クラウドインフラエンジニアなど職種問わず、様々な技術領域にチャレンジできます。また、PM(プロジェクトマネージャー) や EM(エンジニアリングマネージャー)のキャリアパスも用意しています。
興味のある方は Wantedly,typeの募集をぜひ読んでください!

お知らせ

最後に、toraco株式会社では2024年11月1日にエンジニア向けのコミュニティを立ち上げました。
Discord のサーバーで運営しており、以下のリンクから無料で参加できます。コミュニティ内では以下のような投稿・活動がされます!

https://discord.gg/pxfMjDfsge

  • もくもく会・作業ラジオ・雑談部屋などオンライン上での交流
  • オフラインイベントの案内
  • 代表の稲垣(トラハック)が公開するコンテンツの説明・質問回答
  • toraco株式会社からの副業や案件の紹介
  • フロントエンド関連技術の情報共有および議論
  • 生成AI関連技術のキャッチアップ
  • その他、技術領域にこだわらない情報共有および議論
toraco株式会社のテックブログ

Discussion