スキップしてメイン コンテンツに移動

QuarkusでGraphQLを扱う

近頃定期的に、RESTful APIいらない、GraphQL最高。
複数クライアント用のBFFをGraphQLにしてOne Size Fit All(OSFA)で対応する!
みたいな話を見聞きすることが度々あってモヤモヤしていた。

特に自分はスキーマ駆動開発でWeb APIを作ってそのスキーマからクライアントサイドのクラスもサーバーサイドのクラスも作り、Web APIを含む開発を楽にするぞ、というあたりの動きを取ることが多いので、それがいらない、あるいはいらないと思われるほどメリットがあまりあるという状況ならキャッチアップ必須と思ったため。

でまあ、雑に言えば、クライアント側の実装の制約がないならBFFはGraphQLでいいのではとは思う状況。
ただし、複数クライアント向けにOSFAで対応するのには現時点では反対。
相当に近しいユースケースならOKだと思いつつ、結局そのBFFにしたGraphQLをアップデートする際になぜ無関係の箇所まで停止の影響を受ける必要があるのか?同じ名称が定義できないなどでネーミングルールが冗長・厳密なものになっていくのはしんどいのではないか、という思いから。

やりたいイメージ的にはこんな感じ。
Data Storeにはなんらか3rd PartyのAPIの取得済み処理結果が入っているとでも思って貰えばOK。



1-4それぞれの口に対していい感じに対処できるのかを見る意味でまず作りを把握しているのが現状。

ソースコードはここに置いた。

思ったより簡単というか、ここのページを参考にGradleでプロジェクトを作って、フォルダ構成をちょっと現実っぽく区分けしたところまでが今。

./gradlew quarkusDev で上がってきた後に http://localhost:8080/graphql-ui/ でGraphQLにクエリを投げられるUIが上がってくる。

今のところ見た感じ、GraphQLを受けるクラスより後ろはRESTful APIの時と同じ感じで、アプリケーションユースケースに従って必要なデータソースからデータを取ってくる処理を書くだけなので、思ったよりも移行に伴うコストは小さく見える。

あとはクライアントサイドから見てどうかとか、もっと複雑なデータを取り扱いたくなったらどうするかとかといったところを見ていけばいいんだろうなという印象を受けている。
ただ、GraphQLをなぜ使いたいのか、どういうシーンで使いたいのか、に根ざしてこの実装の感じが本当にフィットするのかは見極めないといけないなーと思い、過去に読んだGraphQL本を再訪してる。

細かいところで気になったのは、いわゆるリソースクラスを複数持ったらどうなるのか、というところで、簡単な実験をしてみた。
同じクエリ名を持つ2つのクラスにそれぞれGraphQLのためのアノテーション(@GraphQLApi)をつけて呼び出した場合の挙動はどうなるのか。
重複エラーになる、あるいは最初に読み込まれたものだけが読まれる、といったところにあたりをつけていたが、結果は

- (推測の域を出ないが)A-Z順で呼ばれ、クエリ名は先勝ち
- 後から呼ばれたクラスのみに定義されているクエリなどは同様に使えるようになる
- ただし、ホットリロード時はA, Bの状態からAに変更を加えるとBが読み込まれる(First in First Out)

といったところ。
具体的には、

- DummyResource.javaとFilmResource.javaを用意して、それぞれの同じクエリに異なるプリント文を仕込む→Dummy側が呼ばれる
- 上記それぞれの同じクエリに異なる @Name の値を仕込む→Dummy側が呼ばれる
- FilmResource.java側のみにHero系のリソースへのアクセスを書いて呼び出す→呼べる

という感じだった。

Apolloの例とかAWSのAppSyncの例とか見てると、もっと細かく何かと仕込まないといけないのかと思っていたんだけど、今回の実装・準備の仕方に問題がなければ、単にクライアントへのインタフェースがRESTful APIなのかGraphQLなのかという違いだけ、という感じなので受け入れる素地は高まりそう。