RESTful API との比較で GraphQL API を作ることの難しさ

そんなものはない、と思っていた時期が私にもありました。

上の資料でも書いてるんですが、要点を言うと以下のようなことを主張している。

API の設計手法として、以下の2つのパターンが考えられる
・Resource-based API
・Usecase-based API

Usecase-based というのは要はクライアントの要求にそのまま沿った形で API を作るということだ。しかし、UI やその他クライアントの要求というのは変わりやすいものなので、そのたびにいちいち API を変更しないといけないとか、API に一貫性がなくて使いにくいとか、1つの endpoint で多数の要求に対処する "神API" が作られてパフォーマンスが悪化する、というような問題が起こる。

したがって、注意深く RESTful API を設計すると Resource-based になる。ここで言っている Resource というのはテーブル設計にやや近いが、そのままではなく、いわゆるドメインモデルを考察しそれに沿った形で設計されるべきものだ。

この Resource-based API を前提にして考えた時、GraphQL を作るほうがむしろ RESTful API を作るよりも楽なのだ、というのが僕の主張だ。Resource をそのまま GraphQL Type にマッピングして設計すれば、自然とグラフ構造になる。

GraphQL API を作ると N+1 問題が起きやすいので注意が必要、という主張がよく見られる。それは一理あるが、上の立場に立って考えると、それは本来 RESTful API の時でも考えなければならない問題であって、GraphQL 特有の問題ではないことがわかる。むしろ RESTful API で何も考えないと、API リクエストレベルの N+1 が発生してしまうケースだってあるが、GraphQL であれば最悪でも DB レベルの N+1 で済むというメリットになる。

というわけで、最近は自分で API を作るときは GraphQL API 一択だし、万人におすすめしたいと考えていた。しかし、最近ややそうでもないケースがあることに気づいてきた。

上の主張は Resource-based API を設計するという前提において成り立つ。しかし、例えば以下のような状況においては、Resource-based API にこだわること自体が難しい、または間違っているというケースがままある。

  1. Resource を考察するというスキルが不十分である。

  2. Resource を考察することに時間をかけるメリットが少ない。

1と2は複合的なものであるが、とりあえず1について考える。たとえば、これまでサーバーサイドで動的HTMLを作るアプリケーションの開発をしていた人が、Web API 開発をするようになったとき、その間にはそれなりに知識とかパラダイムの転換がある。今までは、いわゆるコントローラー層で、そのページのために必要なデータを準備して渡していたのと同じように API endpoint を作る、という発想が普通だろう。しかしそうすると運用しながら徐々にツラミが出てくるので、少しずつ Resource-based な API に転換していく、という流れが自然だ。

ところが、このような開発者がいきなり GraphQL API を作るとなると、スイッチングコストがあまりに大きい。Web API に関する技術だけでなく GraphQL を学ばなければいけないのに、さらに Resource-based な API の設計手法まで同時に学ぶことは可能だろうか。万全のサポートがあればできるかもしれないし、そうしたほうが良いのは山々だが、実際問題なかなか難しい場面がある。

そうしたときに、拙速に GraphQL を採用してしまうと、GraphQL に適した設計手法 (= Resource-based) を十分学ぶことができず、Usecase-based な思想を引きずったまま GraphQL API を作ってしまうことになる。いわゆる RESTful API, つまり HTTP endpoint で区切られている API の場合、Usecased-based な思想で API を作ったとしても即座に困るわけではない。しかし、GraphQL API でそれをやってしまうとあまりにアンマッチであり、良さを全く活かせないままコストだけを支払うことになる。

もう少し進んで、Resource を考察するということができるようになっても、それを流れるようにできるか、あるいは一定の時間で妥協点を見つけられるか、というのは、やはりスキルによる。そう考えると、特にスタートアップや新規事業などで、ドメインモデルがはっきりしない、あるいは内部品質よりも初期のスピードが重要である、経験豊富な開発者がいない、などの状況においては、ある程度 Usecased-based な API で妥協したほうがよい、そのためには RESTful API を採用したほうが無難なケースもある。

ということで、RESTful API を採用するという選択肢のメリットについてここまで考察してきた。
しかしながら、やはりほとんどのケースにおいて Usecase-based な API に寄せるという判断は「品質を落としてスピードを取っている」類のものだと感じる。たいていそのシワ寄せは数ヶ月単位で来る。

もっというと Resource を考察するという行為はデータベースのテーブル設計を良くすることがほとんどだし、逆にそれをサボると Usecase-based なテーブル設計になるが、より短期間でシワ寄せがくることが容易に想像がつくだろう。逆の路線でもよい、テーブル設計をきちんとすれば、良い Resource-based な API は8割方完成したようなものである。
テーブル設計や API 設計は経験すればするほど上手くなる(良いものを速く作れるようになる)し、自らの成長のためにもサボるべき箇所では決してない。

ということで、自分が関わる範囲ではやはり GraphQL API を勧めていこうという姿勢は変わらない。


追記: (大変良いコメントをもらったので)

まさにこういうことが言いたかった。

さて、実はこれと同じ問題は RESTful API でも起こりうる。その話をする前にすこし RESTful API という語について整理しよう。

この記事では RESTful の意味をあえてぼかして使ってきたが、単に URL + method が endpoint になるもの程度の意味でしか使っていない。(これを RESTful というのは明らかに間違いではあるのだが、いい言葉が当たってないのと世界的に使われてしまっているのが現状なので、40分で書きなぐった記事としては許してほしい。)この記事の以下では、この意味の言葉を RESTish API と呼ぶ。

REST の原義に戻って考えていくと、明らかに Resource-based な API の表現方法として定義されている。なので、RESTful を忠実にやろうとして Resource-based が過剰になってしまうという問題も起きることがある。

自分も RESTish API を作るときに RESTful を極めようとして逆に辛くなるという事例を見たことがある。元ツイートにあるような Resource を見出すのが難しい/コスパ悪いという場面もそうだし、明らかに作っているものが Usecase に強く依存しているにも関わらずそれを Resource を捉えようとしてうまくいかないと悩んでいるみたいな場面もあった。

さて、RESTish API の場合、これは明らかに Usecase に依存しているなとわかれば、割り切って特定の endpoint に Usecase の名前をつけてしまって (GET /usecase_name) それ専用のものにしてしまえばいい。

GraphQL でも同じように「Usecase-based に振り切った戦略」を取ることはできるがかなりやりにくい。GraphQL の場合、Query 直下に置くフィールドはほとんど RESTish API の endpoint と同等なものとみなせるが、さらに GraphQL Type を必ず書かないといけない。そしてそれは、1枚に統合される GraphQL Schema の中にも出てくるから、名前をバッティングしないようにつけないといけない。

この、グローバルな名前空間にすべての GraphQL Type が露出される、という性質が、良くも悪くも Usecased-based に振り切ることを防ぐ。もちろん良い面もある。GraphQL はクエリで大半の Usecase を表現できるから、普通に注意深く設計すれば GraphQL Type が Usecase を表現する必要はあまりないのだ。だが、その設計はどんな場合でも可能なのか/コスパ良いのか、という元の問いに戻ってくる。


noteの通貨流通量を増やしていきたい!!