2019年2月12日

GraphQL Nexusをデータベースと連携させる

GraphQL Nexusは、JavaScript/TypeScript向けのコードファーストでタイプセーフなGraphQLスキーマ構築ライブラリです。Prismaクライアントと新しいnexus-prismaプラグインを使用して、どのようにデータベースに接続できるかをご覧ください。

Using GraphQL Nexus with a Database

⚠️ この記事は古くなっています。これは現在非推奨となっているPrisma 1に関するものです。Prismaの最新バージョンについては、ドキュメントをご覧ください。⚠️

まとめ: GraphQL Nexusによるコードファースト開発

前回の記事では、TypeScriptとJavaScript向けのコードファースト開発を可能にするGraphQLライブラリであるGraphQL Nexusを紹介しました。Nexusでは、GraphQLスキーマがプログラム的に定義され、実装されます。そのため、sangria-graphql(Scala)、graphlq-ruby、またはgraphene(Python)など、他の言語でのGraphQLサーバーの実績あるアプローチを踏襲しています。

本日の記事では、Prismaクライアントと新しいnexus-prismaプラグインを使用して、NexusベースのGraphQLサーバーをデータベースに接続する方法について説明します。後ほど、ブログアプリ向けのGraphQL APIをゼロから構築する実践的な例をご紹介します。

nexus-prismaはPostgreSQL、MySQL、MongoDBで動作します。詳細なドキュメントはこちらをご覧ください


TLDR: nexus-prismaプラグインの利点

  • GraphQLにおけるPrismaモデルのCRUD操作
  • Prismaモデルのカスタマイズ(例: 特定のフィールドを非表示にする、計算フィールドを追加する)
  • 完全なタイプセーフティ: GraphQLスキーマとデータベースのための整合性のある型セット
  • GraphQLエコシステムとの互換性(例: apollo-servergraphql-yoga、など)

nexus-prismaワークフローの理解

ORMの代替としてのPrismaクライアント

Prismaをこれまで使用したことがない方のために、その動作を簡単に説明します

  1. データモデルを定義するか、Prismaに既存のデータベースを内省させる
  2. Prismaクライアント(タイプセーフなデータベースクライアント)を生成する
  3. Prismaクライアントを使用して、アプリケーション(例: GraphQL API)でデータベースにアクセスする

nexus-prismaプラグインの内部動作

nexus-prismaを追加する場合、もう1つのステップがあります。nexus-prisma-generateコード生成CLIを呼び出すことです。これは、Prismaモデル向けの本格的なGraphQL CRUD APIの構成要素を生成します。例えば、Userモデルの場合、以下のものが含まれます

  • クエリ
    • user(...): User!: 単一のレコードを取得する
    • users(...): [User!]!: レコードのリストを取得する
    • usersConnection(...): UserConnection!: リレーコネクション & 集計
  • ミューテーション
    • createUser(...): User!: 新しいレコードを作成する
    • updateUser(...): User: レコードを更新する
    • deleteUser(...): User: レコードを削除する
    • updatesManyUsers(...): BatchPayload!: 複数のレコードを一括で更新する
    • deleteManyUsers(...): BatchPayload!: 複数のレコードを一括で削除する
  • GraphQL入力型
    • UserCreateInput: レコードのすべてのフィールドをラップする
    • UserUpdateInput: レコードのすべてのフィールドをラップする
    • UserWhereInput: レコードのすべてのフィールドのフィルターを提供する
    • UserWhereUniqueInput: レコードの一意なフィールドのフィルターを提供する
    • UserUpdateManyMutationInput: 一括更新が可能なフィールドをラップする
    • UserOrderByInput: フィールドによる昇順または降順の並び順を指定する

UserCreateInputUserUpdateInputは、リレーションフィールドの扱い方が異なります。

nexusnexus-prismaでGraphQLサーバーコードを記述する際、これらの操作を公開し、自身のAPIニーズに合わせてカスタマイズすることで構築します。

Writing GraphQL server code with nexus and nexus-prisma

CRUDの構成要素を生成した後、nexus-prismaprismaObjectTypeを使用して、それらを公開(およびカスタマイズ)し始めることができます。以下のコードスニペットは、Prismaとnexus-prismaに基づいたTODOリストアプリ向けのGraphQL APIを提供する実装を示しています。

私たちはprismaObjectTypeQueryMutationに適用しています。Queryでは、すべてのフィールド(つまりtodotodoestodoesConnection)を保持しています。Mutationでは、公開される操作をカスタマイズするためにprismaFieldsを使用しています。

prismaFieldsは公開する操作を選択することを可能にします。このケースでは、モデルを作成する操作(createTodo)のみを保持したいと考えています。生成されたCRUD構成要素の中から、updateTododeleteTodoも含まれていませんが、特定のTodoにチェックを入れる独自のmarkAsDone(id: ID!)ミューテーションを実装しています。


例: 標準CRUDからカスタマイズされたGraphQL APIへ

それでは、標準的なPrismaのユースケースを簡単に見て、ブログアプリ向けのGraphQL APIを数ステップで素早く構築する方法を確認しましょう。以下がその手順です

  1. TypeScriptを使用してPrismaプロジェクト(無料のデモデータベースを使用)をセットアップする
  2. モデルを定義し、データベースをマイグレートしてPrismaクライアントを生成する
  3. nexus-prisma経由で完全なCRUD GraphQL APIを公開する
  4. nexus-prisma経由でGraphQL APIをカスタマイズする

一緒に作業を進めるには、Prisma CLIがインストールされている必要があります

1) TypeScript、nexusnexus-prismaでPrismaプロジェクトをセットアップする

このセクションは主にプロジェクトのセットアップに関するものです。コードを一緒に書かない場合はスキップしても構いませんが、そうでない場合は以下のセクションを展開してください。

Prisma CLIを使用してシンプルなPrismaプロジェクトを作成する

対話型プロンプトで、以下のオプションを選択します

  1. ブラウザでPrisma Cloudと認証します(必要な場合)
  2. ターミナルに戻り、提案されたすべての値を確定します
  3. ブラウザでPrisma Cloudと認証します(必要な場合)

デモサーバーの代わりに、Dockerを使用してPrismaをローカルで実行することもできます。

次に、nexus-prismaワークフローを設定する必要があります。以下の依存関係を追加します(myblogディレクトリ内)

次に、以下の2行をprisma.ymlの末尾に追加します

これにより、モデルに変更を加えるたびに、Prismaクライアントと生成されたnexus-prismaのCRUD構成要素が確実に更新されます。

TypeScriptを使用しているため、手早くtsconfig.jsonを追加しましょう

最後に、開発に使用するstartスクリプトを追加します。これは、バックグラウンドでファイルを監視し、コードを記述するにつれて生成されたSDLとNexusの型定義を更新する開発サーバーを起動します。これをpackage.jsonに追加してください

2) モデルの定義、データベースのマイグレーション、Prismaクライアントの生成

prisma initコマンドは、datamodel.prismaにデフォルトのUserモデルを作成しました。ブログアプリケーションを構築するため、モデルをアプリケーションドメインに合わせて調整しましょう

次に、データモデルをデータベースに適用してマイグレートする必要があります。以下のコマンドを使用すると、datamodel.prismaで定義された各モデルが基盤となるデータベースのテーブルにマッピングされます

以前にprisma.ymlpost-deployフックを設定したため、PrismaクライアントとCRUD構成要素は自動的に更新されます。

3) nexus-prisma経由で完全なCRUD GraphQL APIを公開する

プロジェクトの初期段階では、APIによって完全なCRUD機能が公開されていると役立つことがよくあります。より制約されたAPI要件は通常、時間とともに現れます。nexus-prismaは、完全なCRUDからカスタマイズされたAPI操作へ移行するための直接的なパスを提供することで、これを完全に考慮しています。

定義されたモデルに対して完全なCRUD(これにはフィルター、ページネーション、ソートが含まれます)を公開するGraphQL APIから始めましょう。index.tsという新しいファイルを作成し、以下のコードを追加してください

この短いチュートリアルではファイル構造にあまり注意を払っていません。適切なセットアップとモジュール化されたスキーマについては、graphql-authの例を確認してください。

npm run startを実行した後、https://:4000でGraphQLサーバーのGraphQL Playgroundを開くことができます。上記で書いたわずかなコードで、すでに本格的なGraphQL CRUD APIが利用可能です。

クエリの例

ミューテーションの例

これはどのように機能するのでしょうか? nexus-prisma-generateは、Prismaモデル(あなたのCRUD構成要素)向けのCRUD APIを提供するGraphQLスキーマを生成しました。このGraphQLスキーマはOpenCRUD仕様に準拠しています。prismaObjectType関数を使用すると、そのスキーマの操作を公開およびカスタマイズできます。

prismaObjectTypeprismaFieldsはホワイトリスト方式を採用しており、公開したいフィールドを明示的にリストアップする必要があります。ワイルドカード演算子*すべてのフィールドを含みます。

Expose full CRUD GraphQL API via nexus-prisma

4) nexus-prisma経由でGraphQL APIをカスタマイズする

このセクションでは、nexus-prismaからのCRUD GraphQL APIをカスタマイズする方法を学びます。具体的には、以下のことを行います。

  1. Userモデルからフィールドを隠す
  2. Postモデルに計算フィールドを追加する
  3. createPostupdatePostミューテーションを隠す
  4. 2つのカスタムcreateDraftpublishミューテーションを追加する

4.1) Userモデルからフィールドを隠す

このセクションでは、Userモデルからemailフィールドを隠します。

モデルをカスタマイズするには、prismaObjectType関数を適用し、definition(t)関数をオプションとして渡す必要があります。

モデルtに対してprismaFieldsを呼び出すことで、公開されるフィールド(およびその引数)をカスタマイズできます。emailがリストに含まれていないため、GraphQL APIから削除されます。

Hide a field from the User model

変更を適用するには、makePrismaSchema内のtypes配列にUserを明示的に渡す必要があります。

エディターが、生成されたCRUD構成要素に基づいて、prismaObjectTypeprismaFieldsに何を渡すべきか提案できることに注意してください。つまり、prismaObjectType('')と入力してCtrl+Spaceを押すと、生成されたすべてのCRUD構成要素の名前が提案されます。t.prismaFields([''])を呼び出すと、tのフィールドが提案されます。

4.2) Postモデルに計算フィールドを追加する

nexus-prismaによる新しいコードファーストアプローチでは、Prismaモデルに計算フィールドを簡単に追加することもできます。例えば、titleを常にすべて大文字で返すフィールドをPostに追加したいとします。その実装方法は以下の通りです。

私たちはgraphql-nexusから提供されるt.string(...) APIを使用して、モデルに新しいフィールドを追加します。これは計算フィールドであるため(したがってnexus-prismaによって自動的に解決されることはありません)、これにリゾルバーをアタッチする必要もあります。

Customize the GraphQL API via nexus-prisma

これまでと同様に、カスタマイズされたPostモデルをtypes配列に明示的に追加する必要があります。

4.3) createPostupdatePostミューテーションを隠す

Userモデルからemailフィールドを隠したのと同じ方法で、生成されたnexus-prisma CRUD構成要素の一部であるQuery/Mutation型から操作を隠すこともできます。

createPostupdatePostを隠すには、再度definition(t)をオプションとしてprismaObjectTypeに渡す必要があります。型に対してprismaFieldsを呼び出した場合、保持したいすべてのフィールドを明示的にリストアップする必要があることに注意してください(空の配列は「操作を何も保持しない」と解釈されます)。

生成されたCRUD GraphQL APIには、バッチ処理とUPSERT操作も含まれていますが、ここでは簡潔にするためにそれらも除外しています。

4. 2つのカスタムcreateDraftpublishミューテーションを追加する

最後に、GraphQL APIに2つのカスタムミューテーションを追加します。それらのSDL定義は以下のようになります

これらのミューテーションを実装するには、Mutation型に2つのフィールド(nexus APIのt.field( ... )を呼び出して)を追加する必要があります。

これを機能させるには、nexusパッケージからstringArgidArgをインポートしてください。

GraphQL Nexusは、GraphQLスキーマのSDLバージョンも生成します。これは./generated/schema.graphqlで見つかります。GraphQL APIの最終バージョンは以下のようになります


コードファーストGraphQL記事からの3つの重要なポイント

これで、コードファーストGraphQLサーバー開発に関する記事シリーズは最終回となります。

GraphQL Nexusnexus-prismaプラグインは、2年以上にわたるGraphQLエコシステムへの積極的な貢献から得た教訓を実装しています。SDLファーストのアプローチではあまりにも多くの問題が見つかったため、現在登場している新しいコードファーストのツールに非常に興奮しています。

私たちは、GraphQL Nexus(およびTypeGraphQLなどの他のコードファーストアプローチ)が、将来のGraphQLスキーマの構築方法を劇的に変えると強く信じています。

このシリーズからの主要なポイントは以下の通りです

  1. コードファーストアプローチは、追加のツールを必要とせず(「必要なツールはプログラミング言語だけ」)、SDLをコミュニケーションツールとしての利点を維持しつつ、言語の慣用的な方法でGraphQLサーバーを構築することを可能にします。
  2. GraphQL Nexusは、開発者が柔軟でタイプセーフなAPIでスキーマを構築できるようにします。自動補完とビルド時エラーチェックのおかげで、開発者は素晴らしい体験を得られます。
  3. nexus-prismaプラグインはPrismaモデルの上に構築されており、開発者が自動生成されたCRUD構成要素を公開およびカスタマイズすることでGraphQL APIを構築できるようにします。

今すぐnexus-prismaを試してみましょう 🙌

nexus-prismaを試す方法はいくつかあります。ドキュメントのGetting Startedセクションに従うか、TypeScript GraphQLの例を探索することができます。

GitHub issueを開くか、Slackで連絡することで、フィードバックを共有してください。


nexus-prismaプラグインにおける素晴らしい仕事をしてくれた、私たちのオープンソースエンジニアFlavian Desverneに心から感謝します💪✨

次回の投稿をお見逃しなく!

Prismaニュースレターに登録する

© . All rights reserved.