APIサーバからのレスポンスは全てハイパーメディア的であるべきだと思ってるんだけど、フロントエンドに重心がある人たちには受け入れられにくいことを知った。
— uたそ (@RoboticsY) April 2, 2023
GraphQL ラブな人たちもいるくらいだから「クライアントが要求するモノ "だけ" 送り返してこい」という思想も分からんでもない。
こういうツイートをしたんですが、ちょっと補足の意味も込めてブログ書きます。
よくあるSPA + APIサーバでのJSONスキーマ
リクエスト
GET: /api/v1/[resource]/[id]
レスポンス
{
"field1": "value1",
"field2": "value2"
}
だいたいこんな感じですよね。リクエストされたリソースをJSONに詰め込んでシンプルに返すだけ。
上記のレスポンスの欠点
上記のやりとりを実現するためにはサーバサイドの仕様をクライアントサイドでも結構知ってないと開発できません。つまりは、アーキテクチャ上は疎結合に見えて、実装レベルで密結合になっています。
ただ、一般的なサイトにおける HTML などのハイパーメディアでは、レスポンスされた内容に関連するコンテンツへのリンクも含まれていたりして、クライアントサイドは最小限の知識だけ持っていれば他のコンテンツにアクセス出来たり、操作できたりします。
つまり、上記のような JSON レスポンスは、Webの利点を取り込んでいないという点において一定の批判があるわけです。
ハイパーメディアとしての JSON
上記の欠点を踏まえて、ただデータを詰めただけの JSON ではなく、関連するリソースへのリンクも同梱しようという考え方があります。 RESTful の成熟度という概念を知っている人向けに言うと、level3 の話をしてます。
標準化も進んでいて、 HAL や HATEOAS などがメジャーです。
もっとも簡易的な方法として、 _links を記載して、自分自身や関連リソースの URI をクライアントに知らせる方法があります。
※HALでは、関連するデータは _embedded に入れたりします。
{
"_links": {
"self": {
"href": "/api/v1/[resource]/[id]"
},
"prev": {
"href": "/api/v1/[resource]/[id - 1]"
},
"next": {
"href": "/api/v1/[resource]/[id + 1]"
}
},
"field1": "value1",
"field2": "value2"
}
ちなみに、仕様が未確定なので下記のように links 内の self などに、href と並んで、許可するHTTPメソッドを記載したり、データを登録・更新する際に送ってきて欲しい JSON の形式を指定したり好き勝手に作ってもいいと思います。
(標準化されるとライブラリが出現するので、そこに乗っかっておいた方がいいですが。)
{
"_links": {
"self": {
"href": "/api/v1/[resource]/[id]",
"allow": ["GET", "UPDATE", "DELETE"],
"schema": {"field1": null, "field2": null}
},
"new": {
"href": "/api/v1/[resource]/",
"allow": ["POST"],
"schema": {"field1": null, "field2": null}
}
},
"field1": "value1",
"field2": "value2"
}
ハイパーメディアに対しての否定的な意見
仕様の理解にコストがかかるとか、レスポンスのサイズが大きくなるなどの批判が一般的です。
難易度などの理由で開発者の時間を奪う仕様は確かに良くないですね。これを難しいと思うか、簡易だと思うかはチームの成熟度によって判断すればいいと思います。無理に導入する必要はないです。
レスポンスのサイズが肥大化するという批判は、ごもっともな気もしますが、SPAとかで最初にJSの塊を読み込むことに比べれば微々たる差分だと個人的には思います。滞在時間が長くて、APIの利用頻度が高い場合はチリツモで効いてくるかもしれないですね。
宣伝
フリーランスのエンジニアとして活動してます。エンジニアとしてシステム開発に参画することもできますし、取引先によっては若手の育成をしながら開発したり、アドバイザーに近いポジションで入ったりもしています。最近は外部PMのような形で開発に関わることも増えてきました。
カジュアルに話す場をご用意できますので、下記のフォームよりご連絡ください。