Apollo Server の v3 と v4 における変更内容について調べる
この記事は Apollo Server の version 3 および 4 における大まかな変更内容と背景について調べた自分用のメモです。
バージョンアップの詳細な影響については公式ドキュメントの Migration guide をご覧ください。
背景
2022 年 11 月に Apollo Server v4 がリリースされた。
v4 リリースに伴い v2/v3 は既に Deprecated となっており、2023 年 10 月 22 日をもって EOL となる。Deprecated となってもセキュリティパッチの対応は引き続き行われるが、明記されている終了日が過ぎると EOL となり全てのサポートやメンテナンスが打ち切られる。
npm のレジストリから削除されることは無いのでインストールすることは可能だが、当然ながら推奨はされない。
Apollo Server は2021 年 7 月に v3 がリリースされた。v2 のリリースは 2018 年 7 月なので、間隔が短くなっている。個人的な意見として、立て続けにメジャーアップデートが行われたことで「この前バージョン上げたばかりなのにもう EOL になるのか...」と不安を覚えた。
移行について調べる中で Apollo Server の tech lead を名乗る人物が最近の状況について Reddit に投稿していた長文を見つけた。
これを読んで面白かったので v3/v4 の変更内容と背景が整合しているかを軽く調べてみることにした。なお、上記の Reddit の投稿は公式のロードマップ v3 / v4 に書かれている内容やその始まりとなった Issue #3184 とも整合している。
Apollo Server の役割について
Apollo Server は GraphQL サーバーの一種で、様々なデータソースに接続してグラフ構造のデータを返すことができる。
そもそも GraphQL とは
- HTTP の POST リクエストで
- GraphQL のクエリや引数を含む JSON を送り
- レスポンスを JSON で受け取る
ためのクエリ言語とその実行環境であり Apollo Server を使わなくても GraphQL API サーバーを作ることはできる。Apollo Server を使う主な理由としては、GraphQL API のリクエストやレスポンスを扱う上で便利な機能があるため。例えば以下のような機能がある。
-
プラグイン機構
- GraphQL リクエストや Web サーバーのライフサイクルイベントにフックして処理を追加できる
- https://www.apollographql.com/docs/apollo-server/integrations/plugins-event-reference
-
Apollo Studio との統合
- Apollo Studio は GraphQL クエリのための IDE のようなもの
- スキーマを基にクエリや引数を補完してくれる
-
キャッシュ
- GraphQL スキーマのフィールドごとに cache の動作を設定できる
- スキーマで静的に定義することもできるし、リゾルバで動的に定義することもできる
-
persisted query
- サーバー側にクエリ文字列とその識別子である SHA-256 ハッシュがキャッシュされる
- クライアントはクエリ文字列の代わりに識別子を送ることで、リクエストに含まれる文字列のサイズを減らすことができる
- ハッシュを GET リクエストで送信し CDN でキャッシュさせるなどの使い道がある
GraphQL のクエリ解析などは GraphQL.js が行うので、Apollo Server は実質的には TypeScript/JavaScript の Web サーバーと との間をくっつけるアダプタのような役割を果たしているといえる。
変更内容
v3
公式の Migration guide を読むと変更点が書いてある。
v3 で削られた機能
- ビルトインされていた外部パッケージとの統合が削除された
-
subscriptions-transport-ws
による WebSocket ベースの GraphQL Subscription が削除された https://www.apollographql.com/docs/apollo-server/v3/migration#subscriptions - 組み込みのファイルアップロード(
graphql-upload
を使う)が削除された https://www.apollographql.com/docs/apollo-server/v3/migration#file-uploads
-
- GraphQL Playground が削除された https://www.apollographql.com/docs/apollo-server/v3/migration/#graphql-playground
- 代わりに Apollo Studio を使う
- v2 で ApolloServer クラスコンストラクタのオプションとして提供されていた機能が plugin として切り出され、コンストラクタから削除された
- graphql-extensions のサポートが削除された https://www.apollographql.com/docs/apollo-server/v3/migration#extensions
- Apollo Server の plugin として書く必要がある
-
apollo-tracing
が deprecated になった https://www.apollographql.com/docs/apollo-server/v3/migration#tracing - playground や cacheControl がコンストラクタから削除された
- graphql-extensions のサポートが削除された https://www.apollographql.com/docs/apollo-server/v3/migration#extensions
- v2 で外部のパッケージから import して re-export していた symbol が削除された https://www.apollographql.com/docs/apollo-server/v3/migration#exports-from-graphql-tools
v3 で追加・変更された機能
- plugin API https://www.apollographql.com/docs/apollo-server/v3/migration/#plugin-api
- plugin event が全て Promise を返すようになった
- v2 では幾つかの plugin event が同期だった
- リクエストの POST ボディが存在しないまたはパースできないときクライアントエラー(4xx)を返すようになった https://www.apollographql.com/docs/apollo-server/v3/migration/#bad-request-errors-more-consistently-return-4xx
- v2 では 5xx を返していた
- フレームワークの integration 周りの変更 https://www.apollographql.com/docs/apollo-server/v3/migration/#changes-to-framework-integrations
-
new ApolloServer()
後にstart()
するのが必須になった(v2 では任意) -
applyMiddleware
やgetMiddleware
する前にstart()
する必要がある -
access-control-allow-origin
ヘッダーのデフォルト値が*
になった
-
v4
公式の Migration guide を読むと変更点が書いてある。
パッケージ構造の変更
v3 以前の Apollo Server では apollo-server-core
が ApolloServer クラスや built-in の plugin やエラークラスを export していたが、v4 ではこれが廃止され @apollo/server
を使うようになった。built-in のエラークラスが削除されるなど後方互換性がない変更があった。
Web アプリケーションフレームワークとの統合
もともと Apollo Server では apollo-server-koa
のような Web アプリケーションフレームワークごとの integration 用パッケージがあり、それを統一する API はなかった。それらのパッケージは Apollo Server の開発チームによってメンテされていた。それぞれ apollo-server-core
から export される ApolloServer のサブクラスとして拡張されており、ユーザーはそれを import して使っていた。
v4 では Apollo Server においてリクエストやレスポンスを扱うための統一された API が定義され、それが各フレームワークの integration から呼ばれるようになった。apollo-server-koa
等の Web アプリケーションフレームワーク向けのパッケージで Apollo によってメンテナンスされていたものは廃止され、@as-integrations/koa のようなコミュニティによってメンテナンスされるパッケージを使うようになった。
v2 では 2018 年時点で Apollo Server が様々なサードパーティのパッケージ(Web アプリケーションフレームワークなど)に対して直接依存しており、共通の API がないため新しい Web アプリケーションフレームワークの統合を追加することが困難だった。また、サードパーティ側のパッケージのバグを Apollo Server の開発チームが修正することもたくさん行われていた。
開発チームとしては Apollo Server と密結合した Web アプリケーションフレームワークなど外部パッケージのバグや脆弱性を修正するのに手間がかかっており、それを改善したい(Apollo の開発チームが修正するのではなく、その外部パッケージを実際に使っている人たちに修正してほしい)という動機があったようだ。
v4 で削られた機能
- Web アプリケーション向けのフレームワークとの統合が廃止
- v4 以降はコミュニティによってメンテナンスされる
@as-integrations/
のパッケージを使う - https://www.apollographql.com/docs/apollo-server/migration#removed-integrations
- v4 以降はコミュニティによってメンテナンスされる
- formatResponse フックが廃止
- https://www.apollographql.com/docs/apollo-server/migration#formatresponse-hook
- willSendResponse は Request lifecycle event の最後に呼ばれるフックで plugin(GraphQL リクエストや Apollo Server のライフサイクルの各フェーズに対応して処理を行うやつ)の実装で使われる
- 例えば...
- 認証や認可に用いるアクセストークンを作る Mutation を呼び出した際にそれを Cookie に設定するとか
- リクエストコンテキストから cache の policy を取り出してそれを Cache-Control ヘッダに設定するとか
- CORS の origin 設定や HTTP リクエスト body の解析を行うための設定が廃止
- https://www.apollographql.com/docs/apollo-server/migration/#body-parser-and-cors
- Apollo Server の機能としては廃止されたので、自分で設定する必要がある
- built-in のエラークラスが廃止
- https://www.apollographql.com/docs/apollo-server/migration/#built-in-error-classes
- GraphQLError をカスタマイズして自分でエラークラスを定義する必要がある
v4 で追加・変更された機能
- built-in の Plugin を import する path が変わる
- 細々した変更
- サーバーレスフレームワークから ApolloServer を start するやり方が変わる https://www.apollographql.com/docs/apollo-server/migration#new-approach-to-serverless-frameworks
- context 初期化関数をバイパスして
executeOperation
に直接 context 値を渡せるようになった https://www.apollographql.com/docs/apollo-server/migration/#executeoperation-accepts-context-value - エラーフォーマットの改善 https://www.apollographql.com/docs/apollo-server/migration#error-formatting-changes
- エラーハンドリング周りの改善 https://www.apollographql.com/docs/apollo-server/migration#improvements-to-error-handling-outside-of-resolvers
- ランディングページ以外の全てのエラー response を
text/plain
ではなくapplication/json
で返すようになった https://www.apollographql.com/docs/apollo-server/migration#improvements-to-error-handling-outside-of-resolvers - drain を設定してないサーバーのシャットダウン中に GraphQL operation を受け取った場合、その操作をログに記録する https://www.apollographql.com/docs/apollo-server/migration#warning-for-servers-without-draining
- Apollo Server がデフォルトでインストールするプラグインを無効化した上で有効なプラグインと組み合わせた場合、サーバーの start() 時に例外を throw する
- plugin API
- GraphQLRequest と GraphQLResponse の型が変わる
- GraphQLRequestContext と GraphQLServerContext の型が変わる
- デフォルトの挙動がいろいろ変わった
- v3.7 で追加された CSRF 防止機能がデフォルトで有効になった
- https://www.apollographql.com/docs/apollo-server/migration#csrf-prevention-is-on-by-default
- プリフライトのないリクエストをブロックするので
graphql-upload
でファイルアップロードする場合はクライアント側でApollo-Require-Preflight
ヘッダーをつける
- 1 つの HTTP リクエストで複数のバッチ処理を行う機能がデフォルトで無効になった
- in-memory キャッシュに使うメモリがデフォルトで bound されるようになった
- https://www.apollographql.com/docs/apollo-server/migration#default-cache-is-bounded
- Apollo Server 3 以前ではキャッシュのメモリが bound されておらず APQ がデフォルトで有効なため、 DoS 攻撃に対して非常に弱かった
- v3.7 で追加された CSRF 防止機能がデフォルトで有効になった
v3 で初めて導入された機能で v4 で破壊的変更をされたものはない。やはり本記事冒頭の Reddit 投稿にもある通り v2 からの破壊的変更が大きすぎるので v3/v4 の 2 回に分けてリリースしたように見える。
今後の Apollo
振り返ってみると、メジャーアップデートで削除された機能はどれも Apollo Server の本質的な役割(TypeScript/JavaScript の Web アプリケーションと GraphQL.js のアダプタ)からすると周辺的な機能であり、追加・変更された機能は本質的な役割を補強するものだった。
私個人の Apollo との向き合い方を考えた結果、本質的な役割に沿った機能を使い依存先を絞っていけばバージョンアップに伴う破壊的変更で影響を受けることは少なそうという結論に至った。いわゆる技術スタックと呼ばれるものは何でもそう言えるかもしれないが...
理想を言えば外部への依存は少なければ少ないほど管理しやすいのだが現実にはそうも言ってられないので、依存するならば
- 明確な役割がある
- それを体現したインターフェイスが定義されている
ものを選ぶのがよさそう。
会社としての Apollo
Apollo Server は主に Apollo Graph Inc. (以下、Apollo 社と呼ぶ)によって開発されている。
Apollo Server だけでなく Apollo Client や Apollo Studio など主要な製品は全て無料だが、何で収益を得ているのだろうか。
収益源
2019 年 9 月〜2022 年 10 月ごろまでは Apollo Team プランという開発のあれを売っていた。それ以前は GraphQL operation(Query や Mutation)の数に応じて課金されていたらしい。
また、企業向けに有償機能 + 技術サポートを売っている。
2022 年 10 月以降は、GraphOS という supergraph(彼らが subgraph と呼ぶ様々な GraphQL API を一箇所に統合するための public なエンドポイント)の実行環境であるクラウドプラットフォームを売っている。
歴史
Apollo 社の創業メンバーは元々 Meteor Development Group (以下、Meteor 社と呼ぶ)という会社で Meteor.js やそのデプロイ先となるサービスを開発していた。
Meteor 社はプロジェクト名に宇宙関連の用語を使う慣習があり、それで NASA のアポロ計画にあやかって名付けられたようだ(YouTube: Transmission - Episode 7: Apollo AKA Reactive GraphQL)。アポロはギリシャ神話で真実を司る神の名前でもあるので、様々なデータソースを GraphQL で統合する Apollo にはある意味ぴったりな名前と言えるかもしれない。
- 2012 年 6 月: Meteor 社が $11.2M を調達した
- https://techcrunch.com/2012/07/25/andreessen-horowitz-keeps-eating-the-software-world-with-11-2-million-investment-in-javascript-framework-company-meteor/
- https://www.vcnewsdaily.com/meteor-development/venture-capital-funding/gwfhbqbcjj
- https://blog.meteor.com/meteors-new-11-2-million-development-budget-7370586949e7
- 2015 年 5 月: Meteor 社が Series B で $20M を調達した
- 2015 年 9 月: GraphQL が Facebook(現 Meta)社によって一般公開された
- このころ Meteor から Apollo GraphQL に重心が移ってそう
- 2016 年 2 月: Apollo GraphQL が表に出てきた
- v1 から v2 への移行ガイドを見ると今とだいぶ違ったっぽい
- https://www.apollographql.com/docs/apollo-server/v2/migration-two-dot/
- v1 の正式リリースは 2017 年 7 月
- https://www.apollographql.com/blog/announcement/apollo-server-1-0-a-graphql-server-for-all-node-js-frameworks-2b37d3342f7c/
- おそらくこの間に Meteor 社から Apollo 社に社名が変更されたか、Apollo 社が新たに設立されている
- 2019 年 6 月: Apollo 社が $22M を調達した
- 2019 年 10 月: Meteor の事業や知的財産権が Tiny という会社に買収された
- 2021 年 8 月: Apollo 社が $130M を調達した。now valued at over $1.5B...
- 2022 年 12 月に従業員の 15% を解雇した。
- https://www.apollographql.com/blog/announcement/ceo-geoff-schmidts-message-to-apollo-employees/
- enterprise 向けの事業は前年比で 100% 以上伸びてるらしい
Discussion