2020年8月20日

TypeScript、PostgreSQL & Prisma を使用したバックエンド:REST、検証、テスト

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

Backend with TypeScript, PostgreSQL & Prisma: REST, Validation & Tests

はじめに

このシリーズの目標は、具体的な問題、つまりオンラインコースの採点システムを解決することで、現代のバックエンドのさまざまなパターン、問題、アーキテクチャを探求し、実証することです。これは、多様なリレーションタイプを備え、実際のユースケースを表現するのに十分な複雑さを持つため、良い例となります。

ライブストリームの録画は上記で利用可能であり、この記事と同じ内容をカバーしています。

このシリーズでカバーする内容

このシリーズでは、バックエンド開発のあらゆる側面におけるデータベースの役割に焦点を当て、以下をカバーします。

トピックパートデータモデリングパート1CRUDパート1集計パート1REST APIレイヤーパート2(現在)検証パート2(現在)テストパート2(現在)認証近日公開認可近日公開外部APIとの統合近日公開デプロイメント近日公開

今日学ぶこと

最初の記事では、問題領域のデータモデルを設計し、Prisma Client を使用してデータをデータベースに保存するシードスクリプトを作成しました。

このシリーズの2番目の記事では、最初の記事のデータモデルとPrismaスキーマの上にREST APIを構築します。REST APIの構築にはHapiを使用します。REST APIを使用すると、HTTPリクエストを介してデータベース操作を実行できるようになります。

REST API の一部として、以下の側面を開発します。

  1. REST API: 各モデルのCRUDを処理するためのリソースエンドポイントを持つHTTPサーバーを実装します。APIエンドポイントハンドラーでPrisma Clientにアクセスできるように、PrismaとHapiを統合します。
  2. 検証: ユーザー入力がPrismaスキーマの期待される型と一致することを確認するために、ペイロード検証ルールを追加します。
  3. テスト: 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の事前の知識は必要ありません。Prismaについてはこのシリーズでカバーします。

開発環境

以下がインストールされている必要があります。

  • Node.js
  • Docker(開発用PostgreSQLデータベースの実行に使用)

Visual Studio Codeを使用している場合、構文のハイライト、フォーマット、その他のヘルパーのためにPrisma拡張機能を推奨します。

: Docker を使用したくない場合は、ローカルの PostgreSQL データベース、または Heroku でホストされている PostgreSQL データベースをセットアップできます。

リポジトリをクローンする

このシリーズのソースコードはGitHubで公開されています。

始めるには、リポジトリをクローンして依存関係をインストールします。

注: part-2 ブランチをチェックアウトすることで、同じ開始点から記事を追うことができます。

PostgreSQLを開始する

real-world-grading-app フォルダから以下のコマンドを実行して PostgreSQL を開始します

注: Docker は docker-compose.yml ファイルを使用して PostgreSQL コンテナを開始します。

REST API の構築

実装に入る前に、REST API のコンテキストで関連するいくつかの基本的な概念を見ていきましょう。

  • API: Application programming interface (アプリケーションプログラミングインターフェース)。プログラムが互いに通信できるようにする一連のルール。通常、開発者はサーバー上で API を作成し、クライアントがそれにアクセスできるようにします。
  • REST: 開発者が、HTTPリクエストを介して状態関連の(この場合はデータベースに保存されている状態)操作を公開するために従う一連の規則。例として、GitHub REST APIをご覧ください。
  • エンドポイント: 以下のプロパティ(非網羅的)を持つREST APIへの入り口
    • パス(例: /users/)は、ユーザーエンドポイントにアクセスするために使用されます。パスは、エンドポイントにアクセスするために使用されるURLを決定します(例: www.myapi.com/users/)。
    • HTTPメソッド(例: GETPOSTDELETE)。HTTPメソッドは、エンドポイントが公開する操作のタイプを決定します。例えば、GET /usersエンドポイントはユーザーの取得を許可し、POST /usersエンドポイントはユーザーの作成を許可します。
    • ハンドラー: エンドポイントのリクエストを処理するコード(この場合はTypeScript)。
  • HTTPステータスコード: レスポンスのHTTPステータスコードは、操作が成功したか、エラーが発生したかをAPIコンシューマーに通知します。さまざまなHTTPステータスコードについては、このリストを確認してください。例えば、リソースが正常に作成された場合は201、コンシューマーの入力が検証に失敗した場合は400です。

注: RESTのアプローチの重要な目的の1つは、規則に従うことで車輪の再発明を避けるために、HTTPをアプリケーションプロトコルとして使用することです。

APIエンドポイント

API は以下のエンドポイントを持ちます (HTTP メソッド、続いてパス)

リソースHTTPメソッドルート説明UserPOST/usersユーザーを作成(オプションでコースと関連付け)UserGET/users/{userId}ユーザーを取得UserPUT/users/{userId}ユーザーを更新UserDELETE/users/{userId}ユーザーを削除UserGET/usersユーザーを複数取得CourseEnrollmentGET/users/{userId}/coursesユーザーのコース登録を取得CourseEnrollmentPOST/users/{userId}/coursesユーザーをコースに登録(生徒または教師として)CourseEnrollmentDELETE/users/{userId}/courses/{courseId}ユーザーのコース登録を削除CoursePOST/coursesコースを作成CourseGET/coursesコースを複数取得CourseGET/courses/{courseId}コースを取得CoursePUT/courses/{courseId}コースを更新CourseDELETE/courses/{courseId}コースを削除TestPOST/courses/{courseId}/testsコースのテストを作成TestGET/courses/tests/{testId}テストを取得TestPUT/courses/tests/{testId}テストを更新TestDELETE/courses/tests/{testId}テストを削除Test ResultGET/users/{userId}/test-resultsユーザーのテスト結果を取得Test ResultPOST/courses/tests/{testId}/test-resultsユーザーに関連付けられたテストのテスト結果を作成Test ResultGET/courses/tests/{testId}/test-resultsテストの複数のテスト結果を取得Test ResultPUT/courses/tests/test-results/{testResultId}テスト結果を更新(ユーザーとテストに関連付けられているもの)Test ResultDELETE/courses/tests/test-results/{testResultId}テスト結果を削除

注: {} で囲まれたパラメータ(例: {userId})を含むパスは、URL 内に補間される変数を表します。例えば、www.myapi.com/users/13 では userId13 です。

上記のエンドポイントは、それらが関連付けられている主要なモデル/リソースに基づいてグループ化されています。この分類は、保守性のためにコードを個別のモジュールに整理するのに役立ちます。

この記事では、異なるCRUD操作のパターンを説明するために、上記のエンドポイントの一部(最初の4つ)を実装します。完全なAPIはGitHubリポジトリで利用可能です。これらのエンドポイントは、ほとんどの操作に対するインターフェースを提供するはずです。一部のリソースにはリソースを削除するためのDELETEエンドポイントがありませんが、後で追加することができます。

注: 記事全体を通して、「エンドポイント」と「ルート」という言葉は interchangeably に使用されます。これらは同じものを指しますが、「エンドポイント」は REST の文脈で使用される用語であり、「ルート」は HTTP サーバーの文脈で使用される用語です。

Hapi

APIは、検証とテストをすぐにサポートするHTTPサーバーを構築するためのNode.jsフレームワークであるHapiで構築されます。

Hapiは、HTTPサーバーである@hapi/hapiというコアモジュールと、コア機能を拡張するモジュールで構成されています。このバックエンドでは、以下も使用します。

  • 宣言型入力検証のための@hapi/joi
  • HTTPフレンドリーなエラーオブジェクトのための@hapi/boom

HapiをTypeScriptで動作させるには、HapiとJoiの型を追加する必要があります。これは、HapiがJavaScriptで書かれているためです。型を追加することで、豊富なオートコンプリート機能が利用でき、TypeScriptコンパイラがコードの型安全性を確保できるようになります。

以下のパッケージをインストールします。

サーバーの作成

まず、インターフェースとポートにバインドする Hapi サーバーを作成する必要があります。

以下のHapiサーバーをsrc/server.tsに追加します。

まずHapiをインポートします。次に、新しいHapi.server()@types/hapi__hapiパッケージで定義されているHapi.Server型)を、リッスンするポート番号とホスト情報を含む接続詳細で初期化します。その後、サーバーを起動し、実行中であることをログに出力します。

開発中にサーバーをローカルで実行するには、ts-node-devを使用してTypeScriptコードを自動的にトランスパイルし、変更を加えるとサーバーを再起動するnpm devスクリプトを実行します: npm run dev

チェックポイント: ブラウザでhttps://:3000を開くと、以下の内容が表示されるはずです: {"statusCode":404,"error":"Not Found","message":"Not Found"}

おめでとうございます、サーバーの作成に成功しました。ただし、サーバーにはルートが定義されていません。次のステップでは、最初のルートを定義します。

ルートの定義

ルートを追加するには、前のステップでインスタンス化した Hapi serverroute() メソッドを使用します。ビジネスロジックに関連するルートを定義する前に、200 HTTP ステータスコードを返す /status エンドポイントを追加するのが良い慣行です。これは、サーバーが正しく実行されていることを確認するのに役立ちます。

そのためには、server.tsstart関数を一番上に以下を追加して更新します。

ここでは、HTTPメソッド、パス、そしてオブジェクト{ up: true }を返すハンドラーを定義し、最後にHTTPステータスコードを200に設定しました。

チェックポイント: ブラウザでhttps://:3000を開くと、以下の内容が表示されるはずです: {"up":true}

ルートをプラグインに移動する

前のステップでは、ステータスエンドポイントを定義しました。API は多くの異なるエンドポイントを公開するため、それらすべてを start 関数内に定義していると保守性が低下します。

Hapiには、バックエンドをビジネスロジックの独立した部分に分割する方法として、プラグインという概念があります。プラグインは、コードをモジュール化するための効率的な方法です。このステップでは、前のステップで定義したルートをプラグインに移動します。

これには2つのステップが必要です。

  1. 新しいファイルでプラグインを定義します。
  2. server.start() を呼び出す前にプラグインを登録します。

プラグインの定義

src/ 内に plugins という新しいフォルダを作成することから始めます。

src/plugins/ フォルダに status.ts という名前の新しいファイルを作成します。

そして、ファイルに以下を追加します。

Hapiプラグインは、nameプロパティと、プラグインのロジックをカプセル化するregister関数を持つオブジェクトです。nameプロパティはプラグイン名文字列であり、一意のキーとして使用されます。

各プラグインは、標準のサーバーインターフェースを介してサーバーを操作できます。上記のapp/statusプラグインでは、serverregister関数でstatusルートを定義するために使用されています。

プラグインの登録

プラグインを登録するには、server.tsに戻り、以下のようにステータスプラグインをインポートします。

start関数で、前のステップのroute()呼び出しを、以下のserver.register()呼び出しに置き換えます。

チェックポイント: ブラウザでhttps://:3000を開くと、以下の内容が表示されるはずです: {"up":true}

おめでとうございます、ステータスエンドポイントのロジックをカプセル化するHapiプラグインの作成に成功しました。

次のステップでは、ステータスエンドポイントをテストするためのテストを定義します。

ステータスエンドポイントのテストを定義する

ステータスエンドポイントをテストするには、テストランナーとしてJestを、サーバーへのHTTPリクエストをシミュレートするHapiのserver.injectテストヘルパーとともに使用します。これにより、エンドポイントが正しく実装されていることを確認できます。

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.jsondev スクリプトを更新し、src/server.ts の代わりに src/index.ts を起動するようにします。

テストの作成

テストを作成するには、プロジェクトのルートにtestsというフォルダを作成し、その中にstatus.test.tsというファイルを作成して、以下の内容を追加します。

上記のテストでは、beforeAllafterAllが、サーバーの作成と停止のためのセットアップとティアダウン関数として使用されています。

次に、server.inject が呼び出され、ルートエンドポイント / への GET HTTP リクエストをシミュレートします。その後、テストは HTTP ステータスコードとペイロードをアサートし、ハンドラーと一致することを確認します。

チェックポイント: npm test でテストを実行すると、以下の出力が表示されるはずです。

おめでとうございます、ルートを持つプラグインを作成し、そのルートをテストしました。

次のステップでは、アプリケーション全体でPrismaクライアントインスタンスにアクセスできるように、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クライアントをアプリケーションの残りの部分で利用できるようになりました。次のステップでは、ユーザーのルート用のプラグインを定義します。

Prismaプラグインに依存するユーザー経路用プラグインの定義

次に、ユーザーのルート用の新しいプラグインを定義します。このプラグインは、ユーザー固有のルートハンドラーでCRUD操作を実行できるように、Prismaプラグインで定義したPrisma Clientを利用する必要があります。

Hapiプラグインには、他のプラグインへの依存関係を示すために使用できるオプションのdependenciesプロパティがあります。指定すると、Hapiはプラグインが正しい順序でロードされることを保証します。

まず、ユーザープラグイン用の新しいファイルsrc/plugins/users.tsを作成します。

ファイルに以下を追加します。

ここでは、Hapiが最初にPrismaプラグインをロードするように、dependenciesプロパティに配列を渡しました。

これで、Prisma Clientがアクセス可能であることを確認した上で、register関数内でユーザー固有のルートを定義できます。

最後に、プラグインをインポートし、src/server.tsに以下のように登録する必要があります。

次のステップでは、ユーザー作成エンドポイントを定義します。

ユーザー作成ルートの定義

ユーザープラグインが定義されたので、ユーザー作成ルートを定義できます。

ユーザー作成ルートは、HTTPメソッドがPOST、パスが/usersになります。

src/plugins/users.tsregister 関数内に、以下の 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ファイルを作成し、以下の内容を追加することから始めます。

テストはペイロード付きのリクエストを注入し、statusCodeと、レスポンスのidが数値であることをアサートします。

注: テストは、すべてのテスト実行でemailが一意であることを保証することで、一意制約エラーを回避します。

これで、成功するパス(ユーザーを正常に作成する)のテストを作成したので、次に検証ロジックを検証するための別のテストを作成します。これを行うには、無効なペイロード、例えば必須フィールドfirstNameを省略した別のリクエストを以下のように作成します。

チェックポイント: npm test コマンドでテストを実行し、すべてのテストが合格することを確認してください。

ユーザー取得ルートの定義とテスト

このステップでは、まずユーザー取得エンドポイントのテストを定義し、次にルートハンドラーを実装します。

念のため、ユーザー取得エンドポイントはGET /users/{userId}というシグネチャを持ちます。

まずテストを書き、次に実装を行うという方法は、しばしば「テスト駆動開発」と呼ばれます。テスト駆動開発は、実装作業中に変更の正確性を素早く検証するメカニズムを提供することで、生産性を向上させることができます。

テストの定義

まず、ユーザーが見つからない場合にルートが404を返すことをテストします。

users.test.ts ファイルを開き、以下の test を追加します。

2つ目のテストは、正常にユーザーが取得できた場合のハッピーパスをテストします。前のステップで作成したユーザー作成テストで設定されたuserId変数を使用します。これにより、既存のユーザーをフェッチできます。以下のテストを追加します。

まだルートを定義していないため、今テストを実行するとテストは失敗します。次のステップではルートを定義します。

ルートの定義

users.ts (users plugin) に移動し、server.route() 呼び出しに以下のルートオブジェクトを追加します。

ユーザー作成エンドポイントの検証ルールを定義したのと同様に、上記のルート定義では、userId URL パラメータが数値であることを検証します。

次に、getUserHandler 関数を以下のように定義します。

注: findUnique を呼び出す際、Prisma は結果が見つからなかった場合に null を返します。

ハンドラーでは、リクエストパラメータからuserIdが解析され、Prismaクライアントクエリで使用されます。ユーザーが見つからない場合は404が返され、そうでない場合は見つかったユーザーオブジェクトが返されます。

チェックポイント: npm test でテストを実行し、すべてのテストが合格したことを確認してください。

ユーザー削除ルートの定義とテスト

このステップでは、ユーザー削除エンドポイントのテストを定義し、次にルートハンドラーを実装します。

ユーザー削除エンドポイントは、DELETE /users/{userId} というシグネチャを持ちます。

テストの定義

まず、ルートのパラメータ検証のテストを作成します。users.test.tsに以下のテストを追加します。

次に、ユーザー削除ロジックの別のテストを追加します。このテストでは、ユーザー作成テストで作成したユーザーを削除します。

注: 204ステータス応答コードは、リクエストは成功したが、応答にコンテンツがないことを示します。

ルートの定義

users.ts (users plugin) に移動し、server.route() 呼び出しに以下のルートオブジェクトを追加します。

ルートを定義したら、deleteUserHandler を以下のように定義します。

チェックポイント: npm test でテストを実行し、すべてのテストが合格したことを確認してください。

ユーザー更新ルートの定義とテスト

このステップでは、ユーザー更新エンドポイントのテストを定義し、次にルートハンドラーを実装します。

ユーザー更新エンドポイントは、PUT /users/{userId} というシグネチャを持ちます。

ユーザー更新ルートのテストを作成する

まず、ルートのパラメータ検証のテストを作成します。users.test.tsに以下のテストを追加します。

ユーザー更新エンドポイントの別のテストを追加します。このテストでは、ユーザーのfirstNamelastNameフィールドを更新します(ユーザー作成テストで作成されたユーザーの場合)。

ユーザー更新の検証ルールを定義する

このステップでは、ユーザー更新ルートを定義します。検証の観点から、エンドポイントのペイロードは特定のフィールドを要求すべきではありません(emailfirstNamelastNameが必須であったユーザー作成エンドポイントとは異なります)。これにより、たとえば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ニュースレターに登録する

© . All rights reserved.