コンテンツに移動
API 管理

GraphQL: API コンシューマ向けの一貫したアプローチの構築

2021年4月15日
Google Cloud Japan Team

※この投稿は米国時間 2021 年 4 月 2 日に、Google Cloud blog に投稿されたものの抄訳です。

新しいモバイルアプリやウェブアプリを開発する際にはアプリケーション プログラミング インターフェース(API)を使用してデータや機能を組み合わせますが、API の操作については通常 RESTGraphQL という 2 つの一般的な選択肢のどちらかを選ぶことになります。

この記事では、両者のアプローチを比較し、GraphQL API の利用者にとって一貫性のあるエクスペリエンスを構築するために利用できる REST API のベスト プラクティスをご紹介します。これらはどちらかが他方よりも優れているというものではなく、同じプロジェクトでなくても同じチーム内で両方を使用できます。ただし、プロジェクトでどのような API を使用するかとは別に、一貫性のあるエクスペリエンスを提供できれば、業務の効率化と高速化につながります。

REST と GraphQL の比較

REST は API が準拠するソフトウェア アーキテクチャ スタイルであり、開発者は標準的な方法でサービスを操作できます。GraphQL は API 用のクエリ言語で、こうしたクエリを実行するためのランタイムです。REST と GraphQL は、リソースを URL として識別してアプリがデータや機能を取得できるという点で似ていますが、多くの違いがあります。

  • GraphQL は 1 つのエンドポイントでデータを交換しますが、REST の場合は複数のエンドポイントが関わってくることが少なくありません。GraphQL リゾルバはフィールドに対してデータを取得します。また、失敗したリゾルバがあっても残りのクエリが有用なデータを取得して返すことができます。この操作パラダイムは複数の REST クエリを実行したときと同様の結果が得られるようになっているため、1 つの GraphQL クエリで複数の REST クエリが置き換えられることもよくあります。

  • GraphQL はデータのオーバーフェッチとアンダーフェッチ、つまり、必要以上に多いまたは極端に少ない情報がフェッチされることを防ぎます。REST API のレゾリューションにはさまざまなレベルがあります。取得するデータが多いものもあれば、少ないものもあります。ですから、たとえば従業員の名前と ID 番号のみが必要な場合でも従業員のプロフィール全体がフェッチされるなど、データが過剰に取得されてしまうようなケースや、逆に取得できるデータが少なすぎるために何度も API 呼び出しを行わなくてはならないケースが発生します。

  • REST は各種の HTTP メソッドを使用し、通常 JSON を使用してペイロード データを交換します。一方 GraphQL では HTTP POST が最もよく使用され、クエリタイプはプロトコル内で指定します。GraphQL はスキーマ定義言語(SDL)というカスタムクエリ形式も使用します。リクエストで SDL が使用されていてもデータは JSON で返されるため、クライアントはレスポンスを簡単に活用できます。GraphQL クライアント ライブラリは、ReactJS UI フレームワークとのネイティブ統合を備えており、他の言語やパラダイムでも利用可能なため、多くの開発者が使用できるようになりました。

  • 開発者が API を見つける手段も異なります。REST API の場合、API の発見や操作のためにはなんらかのポータルをストアフロントとして利用します。GraphQL では、組み込みのプレイグラウンドがポータルとなっており、開発にも対応します。これは統合開発環境に近く、開発者は新しいクエリをその場で検索できるうえ、タブ補完などの補助機能も利用できます。また、ドキュメントも異なります。REST は通常、OpenAPI 仕様とポータルを使用します。OpenAPI には拡張機能がいくつかあります。たとえば、Apigee SmartDocs は OpenAPI 仕様からインタラクティブなドキュメントを作成します。GraphQL を使用する場合は通常、Graphiql などのスキーマベースのインタラクティブなドキュメントを使用して、開発や GraphQL エンドポイントの操作を行います。

こうした特長により、GraphQL を使用するユースケースは増えてきていますが、導入時に問題が生じる可能性があります。相互運用性が必要なプロジェクトや社内インフラストラクチャの分解を伴うプロジェクトの場合、GraphQL はわずかな API で異なるさまざまなレガシー システムに対応できる便利なツールです。また、セルフサービスのデベロッパー プログラムや関連する成長戦略でも活用できます。このような場合は通常、大企業が API 管理プラットフォームで REST API を利用可能にすることで社内外のイノベーションを促進します。

このようなプログラムでは、API を開発したチームの外で、多くの開発者が、開発チームが想像もしなかった多くの用途にその API を使用します。その点で、従来のインフラストラクチャ中心の API プロジェクトとは異なります。したがって、一貫性があり信頼性が高く直感的に使いやすいエクスペリエンスを開発者に提供することの重要性が高まります。また、これは GraphQL を導入する際の課題の一つにもつながります。具体的に言えば、REST の場合は一連の API をざっと見れば比較的簡単にそれらがどのような機能を持ち、どのように使えばよいかを直感的に理解できますが、GraphQL ではまだそれができません。

GraphQL で REST ベースのプラクティスを使用する

ジョブでは GraphQL と REST の両方が使用される可能性があるので、そのようなジョブに最適なツールを積極的に使用する必要があります。GraphQL による生産性を高めるには、長年にわたって Google が開発者プログラムの構築で培ってきた REST ベースのベスト プラクティスの一部を採用することをおすすめします。

API は企業がアセットを使用するためのデジタル プロダクトであると考えます。また、アセットをよりよく活用するためには、開発者が API を使用できるようにします。この場合の開発者には社内の従業員、パートナー、外部顧客のすべてを含みます。API はデジタル プロダクトなので、開発者が API の使用方法を理解し、魅力的なエクスペリエンスを市場に提供するためには、一貫性のあるエクスペリエンスが必要です。API の採用やデジタル企業の成長戦略において、デベロッパーの負荷は大きな課題となります。そのため、REST の場合と同様に一貫性が GraphQL の鍵となります。

グラフを、複数の名詞で定義づけられたデータドリブンの階層構造として扱う

REST アーキテクチャ スタイルの原則の一つは、簡素化された一貫性のあるインターフェースを作成することであり、これによりインフラストラクチャの複雑さが合理化されます。整形式の REST クエリが GET/listEmployeesByDepartment のような形を取ると考える人は誰もいません。これではむしろ Java 関数のように見えます。整形式の REST リソースは GET /Employees、POST /Employees など複数の名詞を使用します。使い方を予測しやすい仕様にすることで、REST API は開発者がリソースを使用して新しいエクスペリエンスを構築する速度に直接影響を与えます。時は金なりです。

GraphQL のスキーマでは、カタログ内の本のタイトルや著者などのエンティティ間の関係を定義するのにグラフの階層を使用します。これは基本的にデータドリブンの階層構造ですが、Java 関数のような機能的階層構造として扱われることもあります。このせいで、予測可能かつ直感的で一貫性のあるエクスペリエンスが妨げられ、負荷が生じる可能性があります。

整形式の GraphQL は整形式の REST と同じような形になるようにしましょう。GET /Books ができるなら POST /Books もできると考えるのが自然です。これを、データベースの名詞ではなく、GET listBooksByGenre などの動詞ベースの関数で定義された Java に似た構造と比較してみましょう。POST するにはどうすればよいでしょうか?対象は /BooksByGenre にすべきなのか、/Books なのか、それとも /listBooks なのかは誰もわかりません。ですから、データドリブンのアプローチをとり、グラフをデータドリブンの階層構造として扱うことをおすすめします。

REST が合理的な場合に GraphQL を強制しない

REST では、特にコマンドクエリ責務分離(CQRS)などのパターンを使用する場合、ユーザーはさまざまな URL からデータのリクエストと送信を行うことがよくあります。CQRS は Martin Fowler によって初めて確認されたデザイン パターンで、データを読み取るモデルとデータを更新するモデルを分離します。開発者は多くの場合、REST で CQRS を使用して、マイクロサービス アーキテクチャの複数のサービスからデータを取得します。

GraphQL では、ミューテーション(GraphQL デベロッパーがデータを送信する方法)は、特にデータ型が多種多様な場合や送信されるデータがほとんどない場合に、きわめて迅速に複雑になる可能性があります。データの取得と送信を分離する CQRS と同様のスタイルを使用することをおすすめします。これは大企業、特に REST ベースの API レイヤをすでに使用している企業にとって特に有効な可能性があります。GraphQL は API 管理レイヤ上で、あるいはその代替としてデータを取得できますが、データの送信には既存の REST API を使用できます。これは、REST が合理的な場合に GraphQL を強制すべきでないことを示しています。

再利用できるよう最適化する

大企業で GraphQL をデプロイする際には、開発者がさまざまな種類のバックエンドを扱えるようにする必要がある場合に問題に直面することが少なくありません。そのような場合には、多数の業務部門がそれぞれスキーマを部分的に開発し、通常はスキーマ スティッチングやスキーマ連携によって 1 つの包括的なグラフとして開発者に提示されます。データの表現に一貫性がないため、クエリの動作でグラフのさまざまな部分から異なるデータや動作が返される場合に問題が生じます。SDL で変数名が同じに見えるのであれば、異なるデータソースに解決されるという理由だけで、異なる値や形式を返すようにするべきではありません。

さらに、リレーカーソル接続と入力ヒントは、リクエストされているグラフの部分に関係なく、いずれも均一な挙動を示す必要があります。

これはミューテーションでとりわけ問題となります。その理由は、開発者がある方法でスキーマの一部にデータを送信し、そのデータがまた特定のある形式で記録されるようになっている場合、スキーマの別の部分にデータを送信したときにさらに別の形式で記録されても気付けない可能性があるためです。再利用性と API の製品化を最適化する場合、ミューテーションはとりわけ問題となるため、GraphQL でミューテーションの開発と設計を行う方法を特に注意することをおすすめします。

最後に、フィールド名を確認しましょう。同じ名前のフィールド名がスキーマの異なる部分にあるからといって、異なるデータと動作を提供することは、開発者にとっては不親切です。たとえば、スキーマの一部に名、ミドルネーム、姓が想定される名前フィールドがあり、スキーマの別の部分では「姓.名」の形式が想定されている名前フィールドがある場合、こうした不一致のせいで開発者に使ってもらえない可能性があります。

GraphQL ではクエリの効率を最適化するのは簡単ですが、再利用性の最適化を意識的に行いましょう。API によってデベロッパーが混乱する状況を回避することは利益をもたらします。

Video Thumbnail

REST か GraphQL を問わず API は管理が必要なプロダクト

グラフをデータドリブンの階層構造として扱うことから、再利用性とデベロッパーの使用量を最適化することまで、これらのベスト プラクティスのほとんどは 1 つの中心的な考え方に基づいています。それは、成長戦略に役立つ API はデベロッパー向けのプロダクトであるため、デベロッパーの API 使用エクスペリエンスは、API が採用されるかどうかの最も重要な決定要因の一つになるということです。Apigee API 管理を活用して、開発者プログラムはこの考え方を REST API で何年にもわたって採用してきました。企業がその考え方をより広く GraphQL に適用するにつれて、これらの API プログラムは、開発者がイノベーションを実現できるように精通するようになるでしょう。


GraphQL と REST の詳細については、Google Cloud Next の動画をご覧ください。こちらのコミュニティ投稿 を表示し、リファレンス実装への便利なリンクや、Apigee で GraphQL クエリ認可を有効にするツールを提供する GitHubリポジトリへのリンクをご確認いただけます。

- Google Cloud シニア プロダクト マネージャー David Feuer

投稿先