この記事では、SpaceX REST APIを使ったサンプルコードを動かしながら、GraphQLの概要について紹介していければと思います。
最近、AzureのAPI BuilderがGraphQLに対応する(記事投稿時点ではパブリックプレビュー)など、GraphQLの実装コストが下がってきていると感じています。
- 2023年03月 パブリック プレビュー:データ API ビルダーを使用すると、最新のデータベース用の最新の REST エンドポイントと GraphQL エンドポイントを即座に作成できます
- 2023年04月 一般提供:Synthetic GraphQL
今後、GraphQLでの開発が一般的になればより、Webアプリの開発スピードは格段に上がると思います。ここでは、サンプルコードを動かしながらGraphQLの概要を紹介していきます。 GraphQLの魅力が伝わればと思っています!
サンプルコードについて
この記事でお試しするサンプルコードはこちらです。 github.com
このコードは、SpaceXの打ち上げの座席を予約するアプリケーションになっています。
ログイン&Profile機能
宇宙旅行の一覧機能、詳細機能
カート機能
GraphQLとは、何がいいのか
今回使うサンプルコードのデータソースは二つに散らばっており、
- SQLiteに保持したユーザー情報
- r/SpaceX APIから取得するロケットの打ち上げ情報
がありました。 従来のREST APIであれば、それぞれのデータソースに対してリクエストを投げる処理をクライアント上で個別に実装する必要があります。それが、GraphQLの場合は一つのエンドポイントのみで良くなります。
以下の画像はREST APIで実装した場合のアプリケーションとデータソースのやり取りのイメージです。
一つの画面にユーザー情報とロケットの打ち上げ情報を載せたい場合は2回以上のデータソースとのやり取りが発生しいます。 特にモバイル端末の場合は、小さい画面に多くの情報を載せる必要があるため、データソースとクライアントとのやり取りが複雑になりがちです。
それがGraphQLであれば以下のようにエンドポイントが一つに統一され、やり取りが単純化されます!
GraphQLの場合は、エンドポイントが一つにまとまっていることにより、一度のリクエストでまとめて情報を取得することができます。した画像は、SQLiteにあるデータソースとREST APIのデータソースを一度のリクエストで取得した例です。
データソースを取得するときのフロントエンド側の実装コストが減ると、別の端末への対応であったり、新規アプリケーションの構築にも取り組むことができます。 また、GraphQLは既存のREST APIなどをラップしているだけなので、期を見計らって、バックエンド側のModernizationに取り組むことも検討できます。
GraphQLの構築自体がコストであるため、トレードオフの関係ではありますが、フロントエンド側の構築コストが減ることは長い目で見たときにメリットになるのではと思います。
GraphQLとREST APIの比較まとめ
ここまでの内容を簡単に表にまとめました。
GraphQL | REST API | |
---|---|---|
Performance | High リクエストに必要な情報のみを一度で取得できるため、速度は早くなります |
Low 必要な情報を取得するために複数のリクエストをする必要があるため、遅くなる |
Query complexity | Complex エンドポイントを一つにまとめるため、裏のビジネスロジックは複雑になっていく可能性がある。 |
Simple エンドポイントは分離されているため、クエリ自体は単純になる |
Popularity | Still Growing Who's Using |
Very Popular |
Resources & communication support | Growing | Large |
Learning curve | 難しい | 簡単 |
Recommended use case | - マイクロサービスアーキテクチャを採用したアプリケーション - モバイルアプリ |
- シンプルなアプリケーション - 開発の初期段階 |
GraphQLの実装
GraphQLは大きく以下の4つで構成されています。
- Schema(データ型を定義)
- Query(データの取得)
- Mutation(データの更新)
- Resolver(ロジックを定義)
スキーマ
Schemaには型を定義します。
""" Simple wrapper around our list of launches that contains a cursor to the last item in the list. Pass this cursor to the launches query to fetch results after these. """ type LaunchConnection { cursor: String! hasMore: Boolean! launches: [Launch]! } type Launch { id: ID! site: String mission: Mission rocket: Rocket isBooked: Boolean! } type Rocket { id: ID! name: String type: String } type User { id: ID! email: String! profileImage: String trips: [Launch]! token: String } type Mission { name: String missionPatch(size: PatchSize): String } enum PatchSize { SMALL LARGE }
Query
データの取得処理はQueryに定義します。
type Query { launches( """ The number of results to show. Must be >= 1. Default = 20 """ pageSize: Int """ If you add a cursor here, it will only return results _after_ this cursor """ after: String ): LaunchConnection! launch(id: ID!): Launch me: User }
Mutation
データの更新、作成処理はMutationで定義します。
type Mutation { # if false, signup failed -- check errors bookTrips(launchIds: [ID]!): TripUpdateResponse! # if false, cancellation failed -- check errors cancelTrip(launchId: ID!): TripUpdateResponse! login(email: String): User }
Resolver
実際の処理はResolverに書かれます。 コードが長いのでQueryのみ抜粋しています。
ビジネスロジックは全てResolverに書かれていて、Query, Mutation, Schemaには定義のみが書かれています。
Query: { launches: async (_, { pageSize = 20, after }, { dataSources }) => { const allLaunches = await dataSources.launchAPI.getAllLaunches(); // we want these in reverse chronological order allLaunches.reverse(); const launches = paginateResults({ after, pageSize, results: allLaunches, }); return { launches, cursor: launches.length ? launches[launches.length - 1].cursor : null, // if the cursor of the end of the paginated results is the same as the // last item in _all_ results, then there are no more results after this hasMore: launches.length ? launches[launches.length - 1].cursor !== allLaunches[allLaunches.length - 1].cursor : false, }; }, launch: (_, { id }, { dataSources }) => dataSources.launchAPI.getLaunchById({ launchId: id }), me: async (_, __, { dataSources }) => dataSources.userAPI.findOrCreateUser(), },
関連情報
GraphQLでアプリを作るのチュートリアル
Space X-API
サンプルアプリの中で使っていた、Open Sourceとして公開されているREST APIです。
GraphQLが作られた背景
記事の主旨とはずれますが、色々と調べるにあたってGraphQLの全体像が動画でまとまっていて内容がとてもよかったので紹介させてください。動画を見ると、当時GraphQLの前身を作った人たちの興奮が伝わってきます。 2012年頃から既にREST APIに問題意識を持っていたのと、それを技術で解決してしまうのがすごいところと感じました。
この記事には書ききれなかったのでまた別途GraphQLの導入事例などを掘り下げていければと思います。
まとめ
今回は、サンプルコードを例に、GraphQLの特徴をまとめました。 まだWeb上にもGraphQLの情報はそこまで多くなく、採用実績も少ないため、これからの技術だと思います。
今後VR上で動くアプリが増えてきた時に、広い画面で操作することが前提になることから、アプリ上で取得したい情報も増えていくと予想できます。 そういった未来が来た時に、GraphQLのような異なるデータソースをまとめて一つのエンドポイントを提供できる技術というのは有用なのではと感じました。