この記事は、TypeScript、PostgreSQL、および Prisma でバックエンドを構築する一連のライブストリームおよび記事の一部です。この記事では、REST API の構築方法、入力の検証方法、および API のテスト方法について説明します。

はじめに
このシリーズの目標は、具体的な問題を解決することにより、最新のバックエンドのさまざまなパターン、問題、およびアーキテクチャを探求し、実証することです。オンラインコースの採点システム。これは、多様な関連タイプを備えており、現実世界のユースケースを表現するのに十分な複雑さであるため、良い例です。
ライブストリームの録画は上記で利用可能であり、この記事と同じ内容を網羅しています。
シリーズで取り上げる内容
このシリーズでは、バックエンド開発のあらゆる側面におけるデータベースの役割に焦点を当て、以下をカバーします。
トピック | パート |
---|---|
データモデリング | パート 1 |
CRUD | パート 1 |
集計 | パート 1 |
REST API レイヤー | パート 2 (現在) |
バリデーション | パート 2 (現在) |
テスト | パート 2 (現在) |
認証 | 近日公開 |
認可 | 近日公開 |
外部 API との統合 | 近日公開 |
デプロイメント | 近日公開 |
今日学ぶこと
最初の記事では、問題領域のデータモデルを設計し、Prisma Client を使用してデータをデータベースに保存するシードスクリプトを作成しました。
このシリーズの2番目の記事では、最初の記事のデータモデルとPrismaスキーマの上にREST APIを構築します。Hapiを使用してREST APIを構築します。REST APIを使用すると、HTTPリクエストを介してデータベース操作を実行できます。
REST APIの一部として、次の側面を開発します。
- REST API:さまざまなモデルのCRUDを処理するためのリソースエンドポイントを備えたHTTPサーバーを実装します。APIエンドポイントハンドラー用のPrisma Clientへのアクセスを許可するようにPrismaをHapiと統合します。
- バリデーション:ユーザー入力がPrismaスキーマの予期されるタイプと一致するように、ペイロード検証ルールを追加します。
- テスト:JestとHapiの
server.inject
を使用してRESTエンドポイントのテストを作成し、HTTPリクエストをシミュレートして、RESTエンドポイントの検証と永続化ロジックを検証します。
この記事の終わりまでに、CRUD(作成、読み取り、更新、削除)操作とテストのエンドポイントを備えたREST APIが完成します。RESTリソースは、HTTPリクエストをPrismaスキーマのモデルにマッピングします。例:GET /users
エンドポイントは、User
モデルに関連付けられた操作を処理します。
このシリーズの次のパートでは、リストの他の側面について詳しく説明します。
注:ガイド全体を通して、ステップを正しく実行したかどうかを検証できるさまざまなチェックポイントがあります。
前提条件
前提知識
このシリーズでは、TypeScript、Node.js、およびリレーショナルデータベースの基本的な知識を前提としています。JavaScript の経験はあるが、TypeScript を試したことがない場合でも、問題なく理解できるはずです。このシリーズでは PostgreSQL を使用しますが、ほとんどの概念は MySQL などの他のリレーショナルデータベースにも当てはまります。さらに、REST の概念に慣れていると役立ちます。それ以外に、Prisma に関する事前の知識は必要ありません。それはシリーズで取り上げられます。
開発環境
以下がインストールされている必要があります。
Visual Studio Code を使用している場合は、Prisma 拡張機能が、構文の強調表示、フォーマット、およびその他のヘルパーとして推奨されます。
注:Docker を使用したくない場合は、ローカル PostgreSQL データベースまたはHeroku でホストされる PostgreSQL データベースをセットアップできます。
リポジトリのクローン
シリーズのソースコードは、GitHubにあります。
開始するには、リポジトリをクローンし、依存関係をインストールします。
注:
part-2
ブランチをチェックアウトすると、記事と同じ開始点から始めることができます。
PostgreSQL の起動
PostgreSQL を起動するには、real-world-grading-app
フォルダーから次のコマンドを実行します。
注:Docker は、
docker-compose.yml
ファイルを使用して、PostgreSQL コンテナを起動します。
REST API の構築
実装に入る前に、REST API のコンテキストに関連する基本的な概念をいくつか説明します。
- API:アプリケーションプログラミングインターフェース。プログラム同士が通信できるようにする一連のルール。通常、開発者はサーバー上に API を作成し、クライアントが API と通信できるようにします。
- REST:開発者が HTTP リクエストを介して状態関連(この場合はデータベースに格納された状態)の操作を公開するために従う一連の規約。GitHub REST APIを例として確認してください。
- エンドポイント:REST API へのエントリポイント。次のプロパティ(網羅的ではない)があります。
- パス、例:
/users/
。これはユーザーエンドポイントにアクセスするために使用されます。パスは、エンドポイントにアクセスするために使用される URL を決定します。例:www.myapi.com/users/
。 - HTTP メソッド、例:
GET
、POST
、およびDELETE
。HTTP メソッドは、エンドポイントが公開する操作のタイプを決定します。たとえば、GET /users
エンドポイントはユーザーの取得を許可し、POST /users
エンドポイントはユーザーの作成を許可します。 - ハンドラー:エンドポイントへのリクエストを処理するコード(この場合は TypeScript)。
- パス、例:
- HTTP ステータスコード:応答 HTTP ステータスコードは、操作が成功したかどうか、およびエラーが発生したかどうかを API コンシューマーに通知します。このリストでさまざまな HTTP ステータスコードを確認してください。例:リソースが正常に作成された場合は
201
、コンシューマー入力が検証に失敗した場合は400
。
注:REST アプローチの主要な目的の 1 つは、HTTP をアプリケーションプロトコルとして使用して、規約に従うことで車輪の再発明を避けることです。
API エンドポイント
API には、次のエンドポイントがあります(HTTP メソッドの後にパスが続きます)。
リソース | HTTP メソッド | ルート | 説明 |
---|---|---|---|
ユーザー | POST | /users | ユーザーを作成します(オプションでコースと関連付けます) |
ユーザー | GET | /users/{userId} | ユーザーを取得します |
ユーザー | PUT | /users/{userId} | ユーザーを更新します |
ユーザー | DELETE | /users/{userId} | ユーザーを削除します |
ユーザー | GET | /users | ユーザーを取得します |
コース登録 | GET | /users/{userId}/courses | ユーザーのコース登録を取得します |
コース登録 | POST | /users/{userId}/courses | ユーザーをコースに登録します(学生または教師として) |
コース登録 | DELETE | /users/{userId}/courses/{courseId} | コースへのユーザーの登録を削除します |
コース | POST | /courses | コースを作成します |
コース | GET | /courses | コースを取得します |
コース | GET | /courses/{courseId} | コースを取得します |
コース | PUT | /courses/{courseId} | コースを更新します |
コース | DELETE | /courses/{courseId} | コースを削除します |
テスト | POST | /courses/{courseId}/tests | コースのテストを作成します |
テスト | GET | /courses/tests/{testId} | テストを取得します |
テスト | PUT | /courses/tests/{testId} | テストを更新します |
テスト | DELETE | /courses/tests/{testId} | テストを削除します |
テスト結果 | GET | /users/{userId}/test-results | ユーザーのテスト結果を取得します |
テスト結果 | POST | /courses/tests/{testId}/test-results | ユーザーに関連付けられたテストのテスト結果を作成します |
テスト結果 | GET | /courses/tests/{testId}/test-results | テストの複数のテスト結果を取得します |
テスト結果 | PUT | /courses/tests/test-results/{testResultId} | テスト結果を更新します(ユーザーとテストに関連付けられています) |
テスト結果 | DELETE | /courses/tests/test-results/{testResultId} | テスト結果を削除します |
注:
{}
で囲まれたパラメーターを含むパス(例:{userId}
)は、URL で補間される変数を表します。例:www.myapi.com/users/13
では、userId
は13
です。
上記のエンドポイントは、関連付けられているメインモデル/リソースに基づいてグループ化されています。この分類は、保守性を高めるためにコードを個別のモジュールに整理するのに役立ちます。
この記事では、上記のエンドポイントのサブセット(最初の4つ)を実装して、さまざまなCRUD操作のさまざまなパターンを示します。完全なAPIは、GitHub リポジトリで入手できます。これらのエンドポイントは、ほとんどの操作のインターフェースを提供する必要があります。一部のリソースにはリソースを削除するためのDELETE
エンドポイントがないものもありますが、後で追加できます。
注:記事全体を通して、エンドポイントとルートという言葉は同じ意味で使用されます。同じものを指しますが、エンドポイントは REST のコンテキストで使用される用語であり、ルートは HTTP サーバーのコンテキストで使用される用語です。
Hapi
API は、Hapi – 検証とテストをすぐにサポートする HTTP サーバーを構築するための Node.js フレームワーク – を使用して構築されます。
Hapi は、HTTP サーバーである@hapi/hapi
という名前のコアモジュールと、コア機能を拡張するモジュールで構成されています。このバックエンドでは、以下も使用します。
@hapi/joi
宣言型入力検証用@hapi/boom
HTTP フレンドリーなエラーオブジェクト用
Hapi を TypeScript で動作させるには、Hapi と Joi の型を追加する必要があります。これは、Hapi が JavaScript で記述されているため必要です。型を追加することにより、豊富なオートコンプリートを利用できるようになり、TypeScript コンパイラーがコードのタイプセーフを保証できるようになります。
次のパッケージをインストールします。
サーバーの作成
最初に、インターフェースとポートにバインドする Hapi サーバーを作成する必要があります。
次の Hapi サーバーをsrc/server.ts
に追加します。
最初に、Hapi をインポートします。次に、リッスンするポート番号とホスト情報を含む接続詳細を使用して、新しいHapi.server()
(@types/hapi__hapi
パッケージで定義されたHapi.Server
型)を初期化します。その後、サーバーを起動し、実行中であることをログに記録します。
開発中にローカルでサーバーを実行するには、npm dev
スクリプトを実行します。これにより、ts-node-dev
を使用して TypeScript コードを自動的にトランスパイルし、変更を加えるとサーバーを再起動します:npm run dev
チェックポイント:ブラウザでhttp://localhost:3000を開くと、次のように表示されるはずです:{"statusCode":404,"error":"Not Found","message":"Not Found"}
おめでとうございます。サーバーを正常に作成しました。ただし、サーバーにはルートが定義されていません。次のステップでは、最初のルートを定義します。
ルートの定義
ルートを追加するには、前のステップでインスタンス化した Hapi server
のroute()
メソッドを使用します。ビジネスロジックに関連するルートを定義する前に、200
HTTP ステータスコードを返す/status
エンドポイントを追加することをお勧めします。これは、サーバーが正しく実行されていることを確認するのに役立ちます。
これを行うには、server.ts
のstart
関数を更新して、次のものを上部に追加します。
ここでは、HTTP メソッド、パス、およびオブジェクト{ up: true }
を返し、最後に HTTP ステータスコードを200
に設定するハンドラーを定義しました。
チェックポイント:ブラウザでhttp://localhost:3000を開くと、次のように表示されるはずです:{"up":true}
ルートをプラグインに移動する
前のステップでは、ステータスエンドポイントを定義しました。API はさまざまなエンドポイントを公開するため、すべてをstart
関数で定義すると、保守が困難になります。
Hapi には、バックエンドを分離されたビジネスロジックの断片に分割する方法としてプラグインの概念があります。プラグインは、コードをモジュール化しておくための無駄のない方法です。このステップでは、前のステップで定義したルートをプラグインに移動します。
これには 2 つのステップが必要です。
- 新しいファイルでプラグインを定義します。
server.start()
を呼び出す前にプラグインを登録します。
プラグインの定義
まず、src/
にplugins
という名前の新しいフォルダーを作成します。
src/plugins/
フォルダーにstatus.ts
という名前の新しいファイルを作成します。
そして、ファイルに次を追加します。
Hapi プラグインは、name
プロパティと、通常はプラグインのロジックをカプセル化するregister
関数を持つオブジェクトです。name
プロパティはプラグイン名文字列であり、一意のキーとして使用されます。
各プラグインは、標準のサーバーインターフェースを通じてサーバーを操作できます。上記のapp/status
プラグインでは、server
はregister
関数でstatusルートを定義するために使用されます。
プラグインの登録
プラグインを登録するには、server.ts
に戻り、次のようにステータスプラグインをインポートします。
start
関数で、前のステップのroute()
呼び出しを、次のserver.register()
呼び出しに置き換えます。
チェックポイント:ブラウザでhttp://localhost:3000を開くと、次のように表示されるはずです:{"up":true}
おめでとうございます。ステータスエンドポイントのロジックをカプセル化する Hapi プラグインを正常に作成しました。
次のステップでは、ステータスエンドポイントをテストするためのテストを定義します。
ステータスエンドポイントのテストの定義
ステータスエンドポイントをテストするには、Jestをテストランナーとして使用し、Hapi のserver.inject
テストヘルパーを組み合わせて、サーバーへの HTTP リクエストをシミュレートします。これにより、エンドポイントを正しく実装したことを検証できます。
server.ts を 2 つのファイルに分割する
server.inject
メソッドを使用するには、プラグインが登録された後、サーバーが起動する前に、テストでserver
オブジェクトにアクセスする必要があります。これにより、テストの実行時にサーバーがリクエストをリッスンするのを防ぐことができます。これを行うには、server.ts
を次のように変更します。
あなたはちょうどstart
関数を 2 つの関数に置き換えました。
createServer()
:プラグインを登録し、サーバーを初期化します。startServer()
:サーバーを起動します。
注:Hapi の
server.initialize()
は、サーバーを初期化(キャッシュを起動し、プラグイン登録を完了)しますが、接続ポートでのリッスンは開始しません。
これで、server.ts
をインポートし、テストでcreateServer()
を使用してサーバーを初期化し、server.inject()
を呼び出して HTTP リクエストをシミュレートできます。
次に、アプリケーションの新しいエントリポイントを作成します。これにより、createServer()
とstartServer()
の両方が呼び出されます。
新しいsrc/index.ts
ファイルを作成し、それに次を追加します。
最後に、package.json
のdev
スクリプトを更新して、src/server.ts
の代わりにsrc/index.ts
を起動するようにします。
テストの作成
テストを作成するには、プロジェクトのルートにtests
という名前のフォルダーを作成し、status.test.ts
という名前のファイルを作成して、ファイルに次を追加します。
上記のテストでは、beforeAll
とafterAll
は、サーバーを作成および停止するためのセットアップ関数とティアダウン関数として使用されます。
次に、server.inject
が呼び出されて、ルートエンドポイント/
へのGET
HTTP リクエストをシミュレートします。次に、テストは HTTP ステータスコードとペイロードをアサートして、ハンドラーと一致することを確認します。
チェックポイント:npm test
でテストを実行すると、次の出力が表示されるはずです。
おめでとうございます。ルートを持つプラグインを作成し、ルートをテストしました。
次のステップでは、アプリケーション全体で Prisma Client インスタンスにアクセスできるように、Prisma プラグインを定義します。
Prisma プラグインの定義
ステータスプラグインを作成した方法と同様に、Prisma プラグイン用の新しいファイルsrc/plugins/prisma.ts
ファイルを作成します。
Prisma プラグインの目標は、Prisma Client をインスタンス化し、server.app
オブジェクトを通じてアプリケーションの残りの部分で使用できるようにし、サーバーが停止したときにデータベースから切断することです。server.app
は、フレームワークの内部との潜在的な競合なしに、サーバー固有のランタイムアプリケーションデータを安全に格納できる場所を提供します。データは、サーバーにアクセスできるときはいつでもアクセスできます。
次のものをsrc/plugins/prisma.ts
ファイルに追加します。
ここでは、プラグインを定義し、Prisma Client をインスタンス化し、server.app
に割り当て、onPostStop
イベントで実行される拡張関数(フックと考えることができます)を追加します。これは、サーバーの接続リスナーが停止した後に呼び出されます。
Prisma プラグインを登録するには、server.ts
でプラグインをインポートし、次のようにserver.register
呼び出しに渡される配列に追加します。
VSCode を使用している場合は、src/plugins/prisma.ts
ファイルのserver.app.prisma = prisma
の下に赤い波線が表示されます。これは、最初に出会うタイプエラーです。行が表示されない場合は、compile
スクリプトを実行して TypeScript コンパイラーを実行できます。
このエラーの理由は、server.app
のタイプを更新せずに変更したためです。エラーを解決するには、prismaPlugin
定義の上部に次を追加します。
これにより、モジュールが拡張され、PrismaClient
タイプがserver.app.prisma
プロパティに割り当てられます。
注:モジュール拡張が必要な理由の詳細については、DefinitelyTyped リポジトリのこのコメントを確認してください。
TypeScript コンパイラーを満足させるだけでなく、これにより、アプリケーション全体でserver.app.prisma
にアクセスするたびにオートコンプリートが機能するようになります。
チェックポイント:npm run compile
を再度実行すると、エラーは出力されなくなります。
よくできました!これで、2 つのプラグインを定義し、Prisma Client をアプリケーションの残りの部分で使用できるようにしました。次のステップでは、ユーザー ルートのプラグインを定義します。
Prisma プラグインへの依存関係を持つユーザー ルートのプラグインの定義
ユーザー ルートの新しいプラグインを定義します。このプラグインは、Prisma プラグインで定義した Prisma Client を利用して、ユーザー固有のルートハンドラーで CRUD 操作を実行できるようにする必要があります。
Hapi プラグインには、他のプラグインへの依存関係を示すために使用できるオプションの依存関係プロパティがあります。指定した場合、Hapi はプラグインが正しい順序でロードされるようにします。
まず、ユーザー プラグイン用の新しいファイルsrc/plugins/users.ts
ファイルを作成します。
ファイルに次を追加します。
ここでは、dependencies
プロパティに配列を渡して、Hapi が最初に Prisma プラグインをロードするようにしました。
これで、Prisma Client にアクセスできることを知って、register
関数でユーザー固有のルートを定義できます。
最後に、プラグインをインポートし、次のようにsrc/server.ts
に登録する必要があります。
次のステップでは、ユーザー作成エンドポイントを定義します。
ユーザー作成ルートの定義
ユーザープラグインが定義されたので、ユーザー作成ルートを定義できます。
ユーザー作成ルートには、HTTP メソッドPOST
とパス/users
があります。
最初に、register
関数内のsrc/plugins/users.ts
に次のserver.route
呼び出しを追加します。
次に、createUserHandler
関数を次のように定義します。
ここでは、server.app
オブジェクト(Prisma プラグインで割り当て)からprisma
にアクセスし、prisma.user.create
呼び出しでリクエストペイロードを使用して、ユーザーをデータベースに保存します。
再度、payload
のプロパティにアクセスする行の下に赤い波線が表示されるはずです。これはタイプエラーを示しています。エラーが表示されない場合は、TypeScript コンパイラーを再度実行してください。
これは、payload
の値が実行時に決定されるため、TypeScript コンパイラーがその型を認識できないからです。これは型アサーションで修正できます。型アサーションは、TypeScript において、変数の推論された型を上書きできるメカニズムです。TypeScript の型アサーションは、コンパイラーよりも型の詳細を理解していることを伝えるためだけのものです。
そのためには、期待されるペイロードのインターフェースを定義します。
注: TypeScript では、型とインターフェースは多くの点で類似しています。
次に、型アサーションを追加します。
プラグインは次のようになります。
ユーザー作成ルートにバリデーションを追加する
このステップでは、Joi を使用してペイロードのバリデーションも追加し、ルートが正しいデータを持つリクエストのみを処理するようにします。
バリデーションは、ランタイムの型チェックと考えることができます。TypeScript を使用する場合、コンパイラーが実行する型チェックは、コンパイル時に知りうる情報に限定されます。ユーザー API の入力はコンパイル時には知りえないため、ランタイムバリデーションがそのような場合に役立ちます。
そのためには、次のように Joi をインポートします。
Joi を使用すると、Joi バリデーションオブジェクトを作成してバリデーションルールを定義できます。これはルートハンドラーに割り当てることができ、Hapi はペイロードをバリデーションすることを認識します。
ユーザー作成エンドポイントでは、ユーザー入力が上記で定義した型に適合することをバリデーションする必要があります。
Joi に対応するバリデーションオブジェクトは次のようになります。
次に、バリデーターオブジェクト userInputValidator
を使用するようにルートハンドラーを設定する必要があります。ルート定義オブジェクトに以下を追加します。
ユーザー作成ルートのテストを作成する
このステップでは、ユーザー作成ロジックを検証するためのテストを作成します。このテストでは、server.inject
を使用して POST /users
エンドポイントにリクエストを送信し、レスポンスに id
フィールドが含まれていることを確認することで、ユーザーがデータベースに作成されたことを検証します。
まず、tests/users.tests.ts
ファイルを作成し、次の内容を追加します。
このテストは、ペイロード付きのリクエストを inject し、statusCode
とレスポンスの id
が数値であることをアサートします。
注: このテストでは、
ハッピーパス(ユーザーの作成が成功した場合)のテストを作成したので、次にバリデーションロジックを検証するための別のテストを作成します。これを行うには、無効なペイロードを持つ別のリクエストを作成します。たとえば、必須フィールド firstName
を次のように省略します。
チェックポイント: npm test
コマンドでテストを実行し、すべてのテストがパスすることを確認します。
ユーザー取得ルートを定義およびテストする
このステップでは、まずユーザー取得エンドポイントのテストを定義し、その後ルートハンドラーを実装します。
念のため、ユーザー取得エンドポイントは GET /users/{userId}
シグネチャを持ちます。
最初にテストを書き、その後実装を行うプラクティスは、しばしばテスト駆動開発と呼ばれます。テスト駆動開発は、実装に取り組んでいる間に変更の正しさを検証するための高速なメカニズムを提供することで、生産性を向上させることができます。
テストを定義する
まず、ユーザーが見つからない場合にルートが 404 を返すことをテストします。
users.test.ts
ファイルを開き、次の test
を追加します。
2 番目のテストは、ハッピーパス、つまりユーザーの取得が成功した場合をテストします。前のステップで作成したユーザー作成テストで設定された userId
変数を使用します。これにより、既存のユーザーをフェッチすることが保証されます。次のテストを追加します。
まだルートを定義していないため、今テストを実行するとテストは失敗します。次のステップでは、ルートを定義します。
ルートを定義する
users.ts
(users プラグイン) に移動し、次のルートオブジェクトを server.route()
呼び出しに追加します。
ユーザー作成エンドポイントのバリデーションルールを定義したのと同様に、上記のルート定義では、userId
URL パラメーターをバリデーションして、数値が渡されることを保証します。
次に、getUserHandler
関数を次のように定義します。
注:
findUnique
を呼び出すと、Prisma は結果が見つからなかった場合にnull
を返します。
ハンドラーでは、userId
がリクエストパラメーターから解析され、Prisma Client クエリで使用されます。ユーザーが見つからない場合は 404
が返され、それ以外の場合は、見つかったユーザーオブジェクトが返されます。
チェックポイント: npm test
でテストを実行し、すべてのテストがパスしたことを確認します。
ユーザー削除ルートを定義およびテストする
このステップでは、ユーザー削除エンドポイントのテストを定義し、その後ルートハンドラーを実装します。
ユーザー削除エンドポイントは DELETE /users/{userId}
シグネチャを持ちます。
テストを定義する
まず、ルートのパラメーターバリデーションのテストを作成します。users.test.ts
に次のテストを追加します。
次に、ユーザー削除ロジックの別のテストを追加します。ここでは、ユーザー作成テストで作成したユーザーを削除します。
注: 204 ステータスレスポンスコードは、リクエストが成功したが、レスポンスにコンテンツがないことを示します。
ルートを定義する
users.ts
(users プラグイン) に移動し、次のルートオブジェクトを server.route()
呼び出しに追加します。
ルートを定義したら、deleteUserHandler
を次のように定義します。
チェックポイント: npm test
でテストを実行し、すべてのテストがパスしたことを確認します。
ユーザー更新ルートを定義およびテストする
このステップでは、ユーザー更新エンドポイントのテストを定義し、その後ルートハンドラーを実装します。
ユーザー更新エンドポイントは PUT /users/{userId}
シグネチャを持ちます。
ユーザー更新ルートのテストを作成する
まず、ルートのパラメーターバリデーションのテストを作成します。users.test.ts
に次のテストを追加します。
ユーザー更新エンドポイントの別のテストを追加します。ここでは、(ユーザー作成テストで作成した)ユーザーの firstName
および lastName
フィールドを更新します。
ユーザー更新バリデーションルールを定義する
このステップでは、ユーザー更新ルートを定義します。バリデーションに関して、エンドポイントのペイロードは特定のフィールドを必須としない必要があります(email
、firstName
、および lastName
が必須であるユーザー作成エンドポイントとは異なります)。これにより、エンドポイントを使用して単一のフィールド(firstName
など)を更新できます。
ペイロードバリデーションを定義するには、userInputValidator
Joi オブジェクトを使用できますが、思い出していただければわかるように、一部のフィールドは必須でした。
ユーザー更新エンドポイントでは、すべてのフィールドはオプションである必要があります。Joi は、tailor
および alter
メソッドを使用して、同じ Joi オブジェクトのさまざまなバリエーションを作成する方法を提供します。これは、コードをDRYに保ちながら、類似したバリデーションルールを持つ作成ルートと更新ルートを定義する場合に特に役立ちます。
すでに定義されている userInputValidator
を次のように更新します。
ユーザー作成ルートのペイロードバリデーションを更新する
これで、src/plugins/users.ts
(users
プラグイン) で createUserValidator
を使用するようにユーザー作成ルート定義を更新できます。
ユーザー更新ルートを定義する
更新用のバリデーションオブジェクトが定義されたので、ユーザー更新ルートを定義できます。src/plugins/users.ts
(users
プラグイン) に移動し、次のルートオブジェクトを server.route()
呼び出しに追加します。
ルートを定義したら、updateUserHandler
関数を次のように定義します。
チェックポイント: npm test
でテストを実行し、すべてのテストがパスしたことを確認します。
まとめと次のステップ
ここまで到達された方は、おめでとうございます。この記事では、REST の概念から始まり、ルート、プラグイン、プラグインの依存関係、テスト、バリデーションなどの Hapi の概念に至るまで、多くの範囲をカバーしました。
Hapi 用の Prisma プラグインを実装し、アプリケーション全体で Prisma を利用できるようにし、それを利用するルートを実装しました。
さらに、TypeScript は、アプリケーション全体でオートコンプリートと(データベーススキーマと同期した)型の正しい使用の検証に役立ちました。
この記事では、すべてのエンドポイントのサブセットの実装について説明しました。次のステップとして、同じ原則に従って他のルートを実装できます。
バックエンドの完全なソースコードは、GitHub で見つけることができます。
この記事の焦点は REST API の実装でしたが、バリデーションやテストなどの概念は他の状況にも当てはまります。
Prisma はリレーショナルデータベースの操作を容易にすることを目指していますが、基盤となるデータベースについてより深く理解していると役立つ場合があります。
データベースの仕組み、適切なデータベースの選択方法、およびアプリケーションでデータベースを最大限に活用する方法の詳細については、Prisma のデータガイドをご覧ください。
シリーズの次のパートでは、以下について詳しく学びます。
- 認証: メールと JWT を使用したパスワードレス認証の実装。
- 継続的インテグレーション: バックエンドのテストを自動化するための GitHub Actions パイプラインの構築。
- 外部 API との統合: トランザクショナルメール API を使用したメールの送信。
- 認可: さまざまなリソースへのさまざまなレベルのアクセスを提供します。
- デプロイメント
次回の投稿をお見逃しなく!
Prisma ニュースレターに登録する