ミドルウェア
非推奨:ミドルウェアはバージョン4.16.0で非推奨になりました。
ミドルウェアの代替として、Prisma Client拡張機能のquery
コンポーネントタイプを使用することをお勧めします。Prisma Client拡張機能は、バージョン4.7.0でプレビューとして初めて導入され、4.16.0で一般提供になりました。
Prisma Client拡張機能を使用すると、独立したPrisma Clientインスタンスを作成し、各クライアントを特定のフィルターまたはユーザーにバインドできます。たとえば、特定のユーザーにクライアントをバインドして、ユーザーの隔離を提供できます。Prisma Client拡張機能は、エンドツーエンドの型安全も提供します。
ミドルウェアはクエリレベルのライフサイクルフックとして機能し、クエリの実行前または実行後にアクションを実行できます。prisma.$use
メソッドを使用してミドルウェアを追加します。以下のように
const prisma = new PrismaClient()
// Middleware 1
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
// Middleware 2
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
// Queries here
バッチトランザクションを使用する場合、ミドルウェア内でnext
を複数回呼び出さないでください。これにより、トランザクションから抜け出し、予期しない結果につながります。
params
は、クエリの名前など、ミドルウェアで使用可能なパラメーターを表し、next
は、スタック内の次のミドルウェアまたは元のPrisma Clientクエリを表します。
ミドルウェアの考えられるユースケースには、以下が含まれます
- フィールド値の設定または上書き - たとえば、ブログ投稿コメントのコンテキスト言語の設定
- 入力データの検証 - たとえば、外部サービスを介して不適切な言語のユーザー入力を確認する
- ソフトデリートを実行するために、
delete
クエリをインターセプトしてupdate
に変更する - クエリの実行にかかった時間をログに記録する
ミドルウェアには他にも多くのユースケースがあります。このリストは、ミドルウェアが対処するように設計されている問題の種類についてのインスピレーションとして役立ちます。
サンプル
次のサンプルシナリオは、実際にミドルウェアを使用する方法を示しています
ミドルウェアサンプル:ソフトデリート
次のサンプルでは、ミドルウェアを使用してソフトデリートを実行します。ソフトデリートとは、レコードをデータベースから実際に削除するのではなく、deletedのようなフィールドをtrueに変更して削除済みとしてマークすることを意味します。ソフトデリートを使用する理由は次のとおりです
ミドルウェアサンプル:ロギング
次の例は、Prisma Clientクエリの実行にかかった時間をログに記録します
ミドルウェアサンプル:セッションデータ
次の例では、各投稿のlanguageフィールドをコンテキスト言語(たとえば、セッション状態から取得)に設定します
ミドルウェアを追加する場所
Prisma Clientミドルウェアをリクエストハンドラーのコンテキスト外に追加してください。そうしないと、各リクエストがミドルウェアの新しいインスタンスをスタックに追加します。次の例は、ExpressアプリのコンテキストでPrisma Clientミドルウェアを追加する場所を示しています
import express from 'express'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
const app = express()
app.get('/feed', async (req, res) => {
// NO MIDDLEWARE HERE
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: true },
})
res.json(posts)
})
実行順序とミドルウェアスタック
複数のミドルウェアがある場合、個別のクエリごとの実行順序は次のとおりです
- 各ミドルウェアの
await next(params)
より前のすべてのロジック(降順) - 各ミドルウェアの
await next(params)
より後のすべてのロジック(昇順)
スタックのどこにいるかに応じて、await next(params)
は次のいずれかを実行します
- 次のミドルウェアを実行する(例のミドルウェア#1と#2)または
- 元のPrisma Clientクエリを実行する(ミドルウェア#3)
const prisma = new PrismaClient()
// Middleware 1
prisma.$use(async (params, next) => {
console.log(params.args.data.title)
console.log('1')
const result = await next(params)
console.log('6')
return result
})
// Middleware 2
prisma.$use(async (params, next) => {
console.log('2')
const result = await next(params)
console.log('5')
return result
})
// Middleware 3
prisma.$use(async (params, next) => {
console.log('3')
const result = await next(params)
console.log('4')
return result
})
const create = await prisma.post.create({
data: {
title: 'Welcome to Prisma Day 2020',
},
})
const create2 = await prisma.post.create({
data: {
title: 'How to Prisma!',
},
})
出力
Welcome to Prisma Day 2020
1
2
3
4
5
6
How to Prisma!
1
2
3
4
5
6
パフォーマンスと適切なユースケース
ミドルウェアはすべてのクエリに対して実行されるため、過度に使用するとパフォーマンスに悪影響を与える可能性があります。パフォーマンスのオーバーヘッドを回避するには
-
不要なロジックの実行を避けるために、ミドルウェアの早い段階で
params.model
およびparams.action
プロパティを確認してくださいprisma.$use(async (params, next) => {
if (params.model == 'Post' && params.action == 'delete') {
// Logic only runs for delete action and Post model
}
return next(params)
}) -
ミドルウェアがシナリオに適したソリューションであるかどうかを検討してください。 例:
- フィールドを設定する必要がある場合、
@default
属性を使用できますか? DateTime
フィールドの値を設定する必要がある場合、now()
関数または@updatedAt
属性を使用できますか?- より複雑な検証を実行する必要がある場合、データベース自体で
CHECK
制約を使用できますか?
- フィールドを設定する必要がある場合、