カスタムバリデーション
Prisma Client クエリのユーザー入力にランタイムバリデーションを追加するには、次のいずれかの方法を使用できます。
- Prisma Client 拡張機能
- カスタム関数
任意のバリデーションライブラリを使用できます。Node.js エコシステムには、高品質で使いやすいバリデーションライブラリが多数あります。以下が含まれます: joi, validator.js, Yup, Zod および Superstruct。
Prisma Client 拡張機能による入力バリデーション
この例では、Zod スキーマを使用して、Prisma Client に渡されるデータが有効であることを確認するために、値の作成および更新時にランタイムバリデーションを追加します。
警告
クエリ拡張機能は現在、ネストされた操作では機能しません。この例では、バリデーションは prisma.product.create()
のようなメソッドに渡されるトップレベルのデータオブジェクトに対してのみ実行されます。この方法で実装されたバリデーションは、ネストされた書き込みに対して自動的に実行されません。
- Prisma Client 拡張機能
- Prisma スキーマ
import { PrismaClient, Prisma } from '@prisma/client'
import { z } from 'zod'
/**
* Zod schema
*/
export const ProductCreateInput = z.object({
slug: z
.string()
.max(100)
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
name: z.string().max(100),
description: z.string().max(1000),
price: z
.instanceof(Prisma.Decimal)
.refine((price) => price.gte('0.01') && price.lt('1000000.00')),
}) satisfies z.Schema<Prisma.ProductUncheckedCreateInput>
/**
* Prisma Client Extension
*/
const prisma = new PrismaClient().$extends({
query: {
product: {
create({ args, query }) {
args.data = ProductCreateInput.parse(args.data)
return query(args)
},
update({ args, query }) {
args.data = ProductCreateInput.partial().parse(args.data)
return query(args)
},
updateMany({ args, query }) {
args.data = ProductCreateInput.partial().parse(args.data)
return query(args)
},
upsert({ args, query }) {
args.create = ProductCreateInput.parse(args.create)
args.update = ProductCreateInput.partial().parse(args.update)
return query(args)
},
},
},
})
async function main() {
/**
* Example usage
*/
// Valid product
const product = await prisma.product.create({
data: {
slug: 'example-product',
name: 'Example Product',
description: 'Lorem ipsum dolor sit amet',
price: new Prisma.Decimal('10.95'),
},
})
// Invalid product
try {
await prisma.product.create({
data: {
slug: 'invalid-product',
name: 'Invalid Product',
description: 'Lorem ipsum dolor sit amet',
price: new Prisma.Decimal('-1.00'),
},
})
} catch (err: any) {
console.log(err?.cause?.issues)
}
}
main()
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Product {
id String @id @default(cuid())
slug String
name String
description String
price Decimal
reviews Review[]
}
model Review {
id String @id @default(cuid())
body String
stars Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
}
上記の例では、Zod スキーマを使用して、レコードがデータベースに書き込まれる前に、実行時にクエリで提供されるデータを検証および解析します。
カスタムバリデーション関数による入力バリデーション
新しいユーザーのサインアップに必要なデータが正しいことを検証するために Superstruct を使用した例を以下に示します。
import { PrismaClient, Prisma, User } from '@prisma/client'
import { assert, object, string, size, refine } from 'superstruct'
import isEmail from 'isemail'
const prisma = new PrismaClient()
// Runtime validation
const Signup = object({
// string and a valid email address
email: refine(string(), 'email', (v) => isEmail.validate(v)),
// password is between 7 and 30 characters long
password: size(string(), 7, 30),
// first name is between 2 and 50 characters long
firstName: size(string(), 2, 50),
// last name is between 2 and 50 characters long
lastName: size(string(), 2, 50),
})
type Signup = Omit<Prisma.UserCreateArgs['data'], 'id'>
// Signup function
async function signup(input: Signup): Promise<User> {
// Assert that input conforms to Signup, throwing with a helpful
// error message if input is invalid.
assert(input, Signup)
return prisma.user.create({
data: input.user,
})
}
上記の例は、ユーザーを作成する前に入力が有効であることを保証する、カスタムの型安全な signup
関数を作成する方法を示しています。
さらに学ぶ
- Prisma Client 拡張機能を使用してクエリに入力バリデーションを追加する方法を学びましょう — 例。
signup
関数をカスタムモデルに移動してコードをより適切に整理する方法を学びましょう。- Prisma Client にユーザーバリデーションを組み込むための未解決の機能リクエストがあります。もしこの機能が実現してほしい場合は、そのイシューに賛成票を投じ、ユースケースを共有してください!