Xでこんな投稿を見かけました。(元のポスト

A)
GET /users/profile
GET /users/settings
GET /users/orders

B)
GET /users?type=profile
GET /users?type=settings
GET /users?type=orders

投稿では「Bの方が圧倒的にスケーラブル」と書かれていました。

しかし、私は最初A一択だと思いました。

実は「スケーラブル」の意味が違っていた

議論を読んでいて気付いたのは、お互いが考えている「スケーラブル」が違うということです。

A派が考えるスケーラビリティ

API設計としてのスケーラビリティです。

  • リソースが分かりやすい
  • レスポンス型が固定
  • OpenAPIを書きやすい
  • SDKを生成しやすい
  • 保守しやすい

例えば

GET /users/profile

を見れば「Profileを取得するAPI」であることが一目で分かります。

新しい機能が増えても

GET /users/security
GET /users/preferences
GET /users/notifications

と自然に追加できます。


B派が考えるスケーラビリティ

一方で投稿者が言っていたのは、インフラ構成の話でした。

例えば

API Gateway
    │
/users?type=profile
    │
Profile Service

/users?type=settings
    │
Settings Service

というように、入口は1つのままで内部サービスだけ増やせるという考え方です。

つまり「エンドポイントを増やさなくても済む」という意味でスケーラブルと言っていました。

でもこれはURL設計とは関係ない

ここで一番違和感がありました。

同じことは

/users/profile
/users/settings
/users/orders

でもできます。

API Gateway
        │
/users/profile  ─▶ Profile Service
/users/settings ─▶ Settings Service
/users/orders   ─▶ Order Service

つまり、サービス分割やスケールアウトはURL設計とは独立した話です。

Aだからスケールできない、Bだからスケールするという話ではありません。

もう一つ気になったこと

Bの設計を突き詰めると、

GET /users?type=profile

だけでは済まなくなります。

そのうち

GET /users?type=profile,settings

GET /users?type=profile&fields=name,email

のようになっていきます。

これは「何を返すか」をクエリパラメータで指定する設計です。

ここまで来ると、RESTというよりGraphQLの発想に近づいていきます。

GraphQLは

query {
  me {
    profile {
      name
    }
    settings {
      theme
    }
  }
}

のように取得したいデータをクライアントが指定します。

つまり、「返すものをクエリで切り替える」という考え方自体がGraphQL寄りなのです。

結論

今回の議論で一番面白かったのは、AかBかではなく、「スケーラブル」という言葉の意味がお互い違っていたことでした。

  • API設計としてのスケーラビリティ
  • インフラ構成としてのスケーラビリティ

この2つを混ぜてしまうと議論は噛み合いません。

個人的には、REST APIとして設計するなら、リソースごとに責務とレスポンスを明確に分けるAの方が自然だと感じています。