LoginSignup
0

posted at

APIのエンドポイント設計で気をつけていること~ポエム編~

この記事は?

日々の業務のなかで、フロントエンドチームの立場でAPIを利用したりバックエンドAPIチームの立場でAPIを設計実装改修したりする私のポエムみたいなものです。
みなさまが日々の業務に疲れたとき、誰かのポエムが見たいときにどうぞ😌
※めちゃくちゃ何番煎じかって内容を含んでます

改めて自己紹介

バックエンド歴多めの一応ハイブリッドエンジニア。
雑に業務経験の言語やツールを列挙すると下記な感じ。

  • バック:Java,PHP,Go,VB.Net,C#,VBScript...
  • フロント:javascript,typescript,React
  • アプリ:Swift
  • AWS:EC2,Lambda,ELB(CLB/ALB),ECS(on Fargate),S3,RDS(Aurora),Amplify,Lightsail,Code3兄弟
  • GCP:GAE,GKE,あんまり、、、

基本スタンスは業務で必要なものは使いながら覚える感じ。
最近作って面白かったのはPuppeteerを使ったラッパーAPI。

とあるmPOSシステムに携わってから人生が転がり始めて、人のつながりのおかげでフリーランスになってバックエンドだけじゃないエンジニアになって今は株式会社スリーシェイクにて日々奮闘中。

設計について

エンドポイント設計はほんとにムズカシイ、その現場やチームの関係性やWebサービスの性質によるとしか言いようがない。
。。。で終わってもしょうがないのでポエム的に思うことを書いてみる。

エンドポイントと言っても2つくらい考えどころがありますよね。

  • 基本のリソース部分や操作に関すること
  • リソース特定や特殊な操作にパスパラメータやクエリパラメータをどう使うか

リソース?操作?

原則、操作するリソースを複数形にすべし、メソッドは操作を表すべし、そうですね。
でも全部それで済むほど単純じゃないことがほとんど。。。
GET /books/1?sort=title&order=asc
シンプルなものはこんな感じになると思いますが、例えば見積書とか作るとき。

POST /estimates (作成)
POST /estimates/download (ダウンロード)
POST /estimates/print (印刷)

どうでしょう?見積書リソースの作成であるPOST実際の見積書のダウンロードや印刷のためのPOSTでエンドポイントを分けたいがためにdownloadprintといったものがパスに含まれています。
一口に操作をメソッドで表現すべき、といってもここらへんどうやって表現するかは人によったりプロジェクトによったり言語によったりになると思います。
まぁ言語仕様をエンドポイントに反映させるな、という原則もありますが笑

ちなみに上記は実際のプロジェクトで私はこのようにしましたという例です。
みなさんはどうしますかね?
クエリパラメータに実際の操作を入れたりする手段もあるとは思いますが、ハンドラ側の分岐が発生しそうでメンテナンス性悪くなりそうなので私は採用しませんでした(ポエム)

パスパラメータ?クエリパラメータ?

対象のリソースを特定する手段をどちらにするか?ですが、私は、というかほとんどの人は恐らく下記の方針にしていると思います。
パスパラメータには「対象のリソースを一意に特定できるものを入れる」
ですね。

例として本の取得APIエンドポイントについて考えたときに一覧が{ドメイン}/booksとして、
bookのidを指定したリソースの取得を下記のどちらにするか、という話です。

{ドメイン}/books/1 (path)
{ドメイン}/books?id=1 (query)

めちゃめちゃ当たり前かもですが、pathのほうが望ましいです、場合によりますが。
これは実際のフロントのURLに照らし合わせても同様の例が多いですよね
Amazonの商品ページとか
https://www.amazon.co.jp/gp/product/B07NDNGQ5H

パスパラメータについては上記の通りで、じゃあクエリパラメータはというとパスパラメータと逆で
「クエリパラメータにはリソースを一意に特定するものを入れない」
ですね、わかりやすい例でいうと、並べ替え検索です。
GET /books/1?sort=title&order=asc
GET /books/1?author=alice
みたいな。
検索はQiitaの検索画面も同様な構成でした。
https://qiita.com/search?q=Qiita&sort=created
他にも、画面上で複数チェックして削除したい、という用途で
DELETE /books?id=1,3,4,5
のような、カンマ区切りで複数指定するという使い方もあります。

私が思うのは(ポエム)

「リソース一覧(たとえば/booksのような)のエンドポイントには全て並べ替え検索のクエリパラメータを用意すべき」
です。
実際の業務であった話で、下記のようなことがありました。

フロントチーム:

  • データの並び順はサーバーでID順にして返してほしい、フロントで並べ替えの処理をするのは性能的にも不利になることが多いから

わかる、めっちゃわかる。
でも、フロントだけで並べ替えを完結させたいときもあるんじゃない?
一覧のテーブルヘッダのクリックで昇順降順とか。
ページングとか複数選択とか絡んでくるとその限りじゃないけど、フロントは絶対並べ替えしません、というのも違うよなぁと思い。

上記に対するAPI側の答えとしては

  • クエリパラメータにsortorderつけてくれればそのとおり返すよ
    と至ってシンプルなのでしたが。

終わりに

まぁほんと、上記で書いたようにAPI側の対応で済んじゃう話ではあるんですが、フロントとAPIどっちがどっちが、というよりはどっちもできて選択できたり、場合によって誰がどうするとか柔軟にサービス作っていきたいよね、と思ったところでした。
そういえば今までのとこでも同じようなやりとりがあったなぁ、どっちがどうするとか、チームの関係性とかサービスの性質もあるけど、改めて設計について考えさせられるなぁ、と思い、ポエムと称して今回書いてみた次第です。

あ、APIがアプリから呼ばれるとなるとまたバージョン違いの話とかで色々面倒になってくるという話も書きたかったんですが、思いのほか長くなってしまったので、それはまた気が向いたときにポエムとして書ければなと思っています。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0