GraphQLとは?
GraphQLは、APIのためのオープンソースのクエリ言語で、2012年にFacebookによって初めて開発され、2015年に一般に公開されました。これは、クライアントが必要な特定のデータのみを要求できる柔軟で効率的な代替手段を提供し、REST APIでよく発生する過剰取得や不足取得の問題を解決します。
GraphQLの人気が高まっている理由の一つは、そのクライアント主導の性質です。これは、パフォーマンス、スケーラビリティ、シームレスなユーザーエクスペリエンスが重要な現代のアプリケーションに特に適しています。GraphQLは、クライアントが複数のリソースを単一のリクエストにまとめることを可能にし、ネットワークトラフィックを削減し、帯域幅が限られているモバイルアプリや複雑なフロントエンドニーズに最適なソリューションとなります。
GitHub、Twitter、Indeed、Shopifyなどの主要企業は、API開発を効率化し、クライアントとサーバーの相互作用を改善する可能性を強調しながら、GraphQLを採用しています。
GraphQLインターフェース
GraphQLにおけるインターフェースは、オブジェクト指向プログラミングのインターフェースと似た機能を持ちます。これは、複数のオブジェクトタイプが実装できる共通フィールドのセットを定義する抽象型です。これにより、クライアントは異なるタイプ間でこれらの共通フィールドを自信を持ってクエリできます。
type Query {
findVehicles(): [Vehicle!]!
}
interface Vehicle {
id: ID!
name: String!
model: String
}
type Car implements Vehicle {
id: ID!
name: String!
model: String
# Specific to Car
fuelType: String!
}
type Bicycle implements Vehicle {
id: ID!
name: String!
model: String
# Specific to Bicycle
gearCount: Int!
isElectric: Boolean!
}
GraphQLクライアントクエリ:
query findVehicles() {
findVehicles() {
vehicle {
id,
name,
model,
... on Car {
fuelType
}
... on Bicycle {
gearCount,
isElectric
}
}
}
}
この例では、Vehicle
インターフェースを実装するすべてのオブジェクトタイプで利用可能な共通フィールドとして、id
、name
、model
があります。しかし、Car
のfuelType
やBicycle
のgearCount
およびisElectric
のようなタイプ特有のフィールドは、フラグメントを使用してクエリできます。
クライアントが共通フィールドのみを必要とする場合、フラグメントを省略できます:
query findCars() {
findCars() {
car {
id,
name,
model
}
}
}
インターフェースを使用するメリット
- コードの再利用性:共通フィールドはインターフェースで定義され、複数のタイプにわたって共有されるため、冗長性が減ります。
- クライアントサイドのロジックの簡素化:クライアントはオブジェクトタイプの条件チェックを必要としません。正確なタイプをリクエストし、自信を持ってレスポンスを処理できます。
- スキーマの拡張性:新しい共通フィールドを追加するのが容易になり、インターフェースで定義するだけで済みます。
- 強制された構造:インターフェースは、すべての実装タイプにわたって共有構造を強制し、一貫性を確保します(例:すべての車両には
id
、name
、model
が必要です)。 - 統一されたクエリ:異なるタイプを個別にクエリするのではなく、クライアントは単一のインターフェースをクエリして、すべての実装タイプからデータを取得できます。
- 改善されたドキュメント:インターフェースを通じて共通の振る舞いを定義することで、API利用者が関連するタイプを理解しやすくなります。
GraphQLユニオン
GraphQLにおけるUnionは、クライアントが単一のフィールドを介して関連する複数のオブジェクトタイプをクエリできる抽象型です。インターフェースとは異なり、ユニオンはメンバータイプが共通のフィールドを共有することを要求しません。これにより、構造が異なる関連タイプを一緒にクエリする必要があるケースを扱うのに理想的です。
type Query {
getPurchaseItems(): [PurchaseItem!]!
}
union PurchaseItem = Product | Service | Subscription
type Product {
id: ID!
productName: String!
price: Float!
}
type Service {
id: ID!
serviceName: String
duration: Float
}
type Subscription {
id: ID!
planName: String
billingCycle: String
}
GraphQLクライアントクエリ:
query getPurchaseItems() {
getPurchaseItems() {
purchaseItems {
... on Product {
id
productName
price
}
... on Service {
id
serviceName
duration
}
... on Subscription {
id
planName
billingCycle
}
}
}
}
この例では、Product、Service、SubscriptionはすべてPurchaseItemユニオンに属する異なるタイプです。クライアントは、これらのフィールドを共有していなくても、単一のクエリでフラグメントを使って3つのタイプすべてをクエリできます。
ユニオンに関する重要な注意事項として、UnionタイプのメンバータイプはすべてObjectベースのタイプでなければなりません。スカラー、インターフェース、ユニオンタイプはユニオンのメンバータイプであってはなりません。同様に、ラッピングタイプもユニオンのメンバータイプであってはなりません。
ユニオンを使用する利点
- 柔軟なグルーピング: ユニオンを使用すると、共通のフィールドを共有しない関連タイプをクエリできるため、そうでなければ扱いにくくなります。
- 簡素化されたエラーハンドリング: クライアントはフラグメントを使って特定のタイプをクエリできるため、クライアント側での複雑な条件ロジックの必要性が減ります。
- 異種データ処理: 単一のクエリで複数のタイプからデータを取得できるため、さまざまなデータ構造の処理が簡素化されます。
- エラー応答に役立つ: ユニオンは、成功応答とエラーの詳細を単一の応答タイプに結合したいときに特に便利であり、クライアントがそれらを効率的に処理できるようにします。
要約
GraphQLインターフェースとユニオンは、GraphQLスキーマを構築するための強力な方法を提供し、柔軟性を高め、クライアントとサーバー間のインタラクションを簡素化します。インターフェースは、タイプ間での共有フィールドを可能にし、コードの再利用性を促進し、スキーマの拡張を容易にします。一方、ユニオンは、共通のフィールドを必要とせずに異なるタイプを一緒にクエリする方法を提供します。
Source:
https://dzone.com/articles/a-beginners-guide-to-graphql-interfaces-and-unions