メインコンテンツにスキップ

ミドルウェア

warning

非推奨:ミドルウェアはバージョン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
warning

バッチトランザクションを使用する場合、ミドルウェア内でnextを複数回呼び出さないでください。これにより、トランザクションから抜け出し、予期しない結果につながります。

paramsは、クエリの名前など、ミドルウェアで使用可能なパラメーターを表し、nextは、スタック内の次のミドルウェアまたは元のPrisma Clientクエリを表します。

ミドルウェアの考えられるユースケースには、以下が含まれます

ミドルウェアには他にも多くのユースケースがあります。このリストは、ミドルウェアが対処するように設計されている問題の種類についてのインスピレーションとして役立ちます。

サンプル

次のサンプルシナリオは、実際にミドルウェアを使用する方法を示しています

ミドルウェアを追加する場所

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)
})

実行順序とミドルウェアスタック

複数のミドルウェアがある場合、個別のクエリごとの実行順序は次のとおりです

  1. 各ミドルウェアのawait next(params)より前のすべてのロジック(降順)
  2. 各ミドルウェアの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制約を使用できますか?