kei615ykhm / logic-loom-nextjs14

LogicLoom is a memo app for engineers created as personal developers. There are no release plans. We will proceed with development while learning practical usage of Next.js, TypeScript, TailwindCSS, Vercel, and Supabase.
0 stars 0 forks source link

`memoSchema.ts`におけるバリデーションエラーメッセージの詳細化 #19

Open kei615ykhm opened 1 month ago

kei615ykhm commented 1 month ago

現在、src/hooks/useMemoManager.tsにて zod のバリデーションを実装した際に学んだ内容を基に、src/schemas/memoSchema.ts に定義されているメモスキーマにバリデーションを追加する作業を進めています。

現状

以下のようなバリデーションを追加しました。

import { z } from 'zod';

export const memoSchema = z.object({
  id: z.string().uuid({ message: "IDは一意である必要があります。" }),
  content: z.string().min(1, { message: "コンテンツは必須です。" }).max(500, { message: "コンテンツは500文字以内で入力してください。" }),
  createdAt: z.string().refine((val) => !isNaN(Date.parse(val)), { message: "作成日は正しい日付形式である必要があります。" }),
});

export type Memo = z.infer<typeof memoSchema>;

問題

バリデーションは機能していますが、現在のエラーメッセージが具体的ではないと感じています。特に、ユーザーにとってわかりやすいエラーメッセージをどう設計すべきかについて悩んでいます。

求める解決策

それぞれのバリデーションエラーメッセージに対して、ユーザーにわかりやすく、かつ具体的な内容を設定したいと考えています。どのようなエラーメッセージが適切か、アドバイスをいただけると幸いです。

kei615ykhm commented 1 month ago

本件について再度確認したい点は、既にいただいているご回答の続きからになります。 そのため、プルリクエストから引用させていただきました。

import { z } from 'zod';

export const memoSchema = z.object({
  id: z.string(),
  content: z.string(),
  createdAt: z.string(),
});

export type Memo = z.infer<typeof memoSchema>;

現時点で、createdAtのバリデーション強化、contentの制約追加、idの一意性保証を行いました。しかし、エラーメッセージの詳細化について理解が不十分です。現在、バリデーションエラーメッセージが具体的でないという問題を認識していますが、それぞれのエラーメッセージにどのような内容を設定すべきかがわかりません。どのようなエラーメッセージを設定すべきか、ご助言いただければ幸いです。

memoSchemaおよびMemoのデータベースでの要件が定まっていないため、現時点でそれぞれの値がどのような形をとっているのが正しいのかというのが見えておらず、そもそも「どういう状況が正しいのか」という要件が存在しないのではないでしょうか? なぜなら、このMemoという型は、本来はデータベースのテーブルの1レコードあたりの形と制限に依存するからです。

なので、たとえば、以下のようにデータベースのスキーマをPrismaで定義する予定だという仮定にしてみます。

// prisma/schema.prisma
model Memo {
  id        String   @id @default(uuid())
  content   String   @db.Text
  createdAt DateTime @default(now())
}

すると、データベースからFetchしたとき、かえってくるべきデータは以下の要件となります。

id:

content:

createdAt:

この要件を満たすためのエラーメッセージ入りのmemoSchemaは以下の通りです。

export const memoSchema = z.object({
  id: z
    .string({ message: 'IDは文字列である必要があります。' })
    .uuid({ message: 'IDは有効なUUID形式でなければなりません。' }),

  content: z
    .string( { messsage: '内容は文字列で定義する必要があります。'} )
    .min(1, { message: '内容は最低1文字必要です。' })
    .max(1000, { message: '内容は1000文字以内でなければなりません。' }),

  createdAt: z
    .string( {messsage: '日付は有効な日付形式文字列で定義する必要があります。'} )
    .refine((val) => !isNaN(Date.parse(val)), { message: '作成日時は有効な日付形式でなければなりません。' }),
});

また、データを取得したものが正しいかを判定するのに使用するzodSchemaとフォームがデータを作成する際にバリデーションを行うためのスキーマは、型も目的も違うので別途定義する必要があります。

フォームから新しいメモを作成する際には、idやcreatedAtはクライアント側で生成する必要がないため、これらのフィールドを除外したスキーマを定義します。

import { z } from 'zod';

/** メモ作成用のスキーマ */
export const createMemoSchema = z.object({
  content: z
    .string({ message: '内容は文字列で定義する必要があります。' })
    .min(1, { message: '内容は最低1文字必要です。' })
    .max(1000, { message: '内容は1000文字以内でなければなりません。' }),
});

/** メモ作成時の型 */
export type CreateMemoInput = z.infer<typeof createMemoSchema>;

Originally posted by @niaka3dayo in https://github.com/kei615ykhm/logic-loom-nextjs14/issues/18#issuecomment-2372570441