Skip to content

Instantly share code, notes, and snippets.

@mesummery
Last active February 11, 2019 03:22
Show Gist options
  • Save mesummery/48893bbca62731e9af8758013f0d5ab3 to your computer and use it in GitHub Desktop.
Save mesummery/48893bbca62731e9af8758013f0d5ab3 to your computer and use it in GitHub Desktop.
learned about aPI

LSUDs & SSKDs

LSUDs(Lerge Set of Unknown Developers)

  • 大多数向けの未知の外部開発者に向けたAPI
  • 誰にでも合うフリーサイズの服にちなんでone-size-fits-all APIとも言う(らしい)

SSKDs(Small Set of Known Developers)

  • 自社サービスのスマートフォンクライアント向けのAPIなど、APIを利用する開発者が限られている
  • APIとしての汎用性よりも、クライアント側でのUXを考える

1スクリーン1APIコール、1セーブ1APIコール

API エンドポイントの設計

原則

覚えやすく、どんな機能をもつURIなのかひと目でわかる。

良いURI

主にLSUDsに向いているポリシー。

  • 短く入力しやすい
  • 人間が読んで理解できる
  • 大文字小文字が混在していない
  • 改造しやすい(Hackable)
  • サーバー側のアーキテクチャが反映されていない
  • ルールが統一されている

短く入力しやすい

  • 長いURLは意味が重複している可能性があるので、見直す

人間が読んで理解できる

  • 英語を用いる
  • 規格や体系化されたもの以外で、省略系を用いない
  • 間違った時制、スペルミスをしない

大文字小文字が混在していない

  • 基本的には全て小文字を用いる

TIPS: GitHub, Tumblr, Foursquareは、混在させると404を返す

改造しやすい(Hackable)

  • URIを修正して別のURIにしやすくする

サーバー側のアーキテクチャが反映されていない

  • 言語や、アーキテクチャがわかると脆弱性になり得るのでやめる

ルールが統一されている

  • クライアントの実装時に混乱を招かない

HTTPメソッド

Name Description
GET リソースの取得
POST リソースの新規登録
PUT 既存リソースの更新
DELETE リソースの削除
PATCH リソースの一部変更
HEAD リソースのメタ情報の取得

GET

  • ブラウザのA要素を使ったリンクはすべてGETとして扱われる
  • GETメソッドに対して、サーバー側の情報の変更処理を書くのはご法度

POST

  • 新規情報を登録するために利用するのが本来の目的
  • 指定したURIの配下にデータを登録する

TIPS: HTML4.0のFormではmethod属性にGETとPOSTしか指定できなくなったので、削除や更新もPOSTでやるのが普及してしまった

PUT

  • 更新したいリソースのURIそのものを指定して、その内容を書き換える
  • 送信したデータでもともとのリソースを書き換える

DELETE

  • URIで指定したリソースを削除する

PATCH

  • 巨大なリソースを丸ごとPUTで書き換えるのが非効率なときなどに、一部書き換えを行う

X-HTTP-Method-Overrideヘッダ

HTMLのFormなど、GETとPOSTのみのサポートしかない場合に、POSTを利用しつつ、メタ情報として「本当は使いたいメソッド」を指定する方法。APIを公開する場合には、この対応をした方が良い。

vs _method

_methodを使う方法もあるが、リクエストデータ中にメタ情報が付与されてしまう。X-HTTP-Method-Overrideヘッダを利用すれば、サーバ側のフレームワークやミドルウェアが自動的に吸収してくれる場合が多い。


エンドポイントの設計例

SNSのWebAPIを想定してみる。 :idはユーザーIDを表すプレースホルダー。

目的 エンドポイント メソッド
ユーザーの一覧取得 http://api.example.com/v1/users GET
ユーザーの新規登録 http://api.example.com/v1/users POST
特定ユーザーの情報の取得 http://api.example.com/v1/users/:id GET
ユーザーの情報の更新 http://api.example.com/v1/users/:id PUT/PATCH
ユーザーの情報の削除 http://api.example.com/v1/users/:id DELETE
ユーザーの友達一覧取得 http://api.example.com/v1/users/:id/friends GET
友達の追加 http://api.example.com/v1/users/:id/friends POST
友達の削除 http://api.example.com/v1/users/:id/friends/:id DELETE
近況の編集 http://api.example.com/v1/updates/:id PUT
近況の削除 http://api.example.com/v1/updates/:id DELETE
近況の投稿 http://api.example.com/v1/updates POST
特定ユーザーの近況の取得 http://api.example.com/v1/users/:id/updates GET
友達の近況一覧の取得 http://api.example.com/v1/users/:id/friends/updates GET

エンドポイントの設計の注意点

  • 複数形の名詞を利用する
  • 利用する単語に気をつける
  • スペースやエンコードを必要とする文字は使わない
  • 単語をつなげる必要がある場合はハイフンを利用する

複数形の名詞を利用する

  • 「集合」を表すため複数形にする
  • 末尾にsをつけない変則的な複数形になる名詞には注意する
  • そもそもリソースを扱っているので動詞は入れない

利用する単語に気をつける

スペースやエンコードを必要とする文字は使わない

  • エンドポイントがどのようなものなのかわからなくなるため
  • パーセントエンコーディングなど愚の骨頂

単語をつなげる必要がある場合はハイフンを利用する

  • ある程度は好みで良いがポリシーがないならハイフンにする
  • そもそも極力単語をつなぎ合わせるのを避けること

クエリパラメータの設計

取得数と取得位置

取得数 取得位置
par_page page
limit offset
count cursor

が、一般的な組み合わせ。

page/per_page vs limit/offset

limit/offsetの方が自由度が高い。 1ページ50アイテムの3ページめ(101アイテムめから)を取得したい場合、

  • per_page=50&page=3
  • limit=50&offset=100

pageは1から、offsetは0から数え始める。

相対位置を利用する問題点

  • パフォーマンスが悪くなる
  • 更新頻度が高いデータでは不整合が起きる

パフォーマンスが悪くなる

MySQLなどのRDBでは、「先頭から何件めか」を調べるために、先頭から数を数える処理が発生するので、データの件数が増えてくるとパフォーマンスが低下する。

更新頻度が高いデータでは不整合が起きる

最初の〇〇件を取得してから、次の〇〇件を取得する間にデータの更新が入ってしまった場合に、ズレが生じる。

絶対位置でデータを取得する

  • データのIDや時刻を記録し、「このIDよりも前」「この時刻より古い」といった指定を行う

TIPS: Twitterのmax_idはこれで、指定したID以前のものを取得するようにしている。

絞り込みのためのパラメータ

qというパラメータ

  • queryの略
  • 検索するフィールドがほぼ1つに決まる場合に用いられることが多い
  • 全文検索(ユーザー情報の中で文書情報が含まれるフィールドすべてが対象)が直感的であるときもある
  • qとフィールド名を組み合わせて検索可能にするケースもある

URIにSearchを入れるべきか

  • 「検索」という意味を明示的に表現する意図としてあり

クエリパラメータとパスの使い分け

  • 一意なリソースを表すのに必要な情報かどうか
  • 省略可能かどうか

一意なリソースを表すのに必要な情報かどうか

  • ユーザーIDなど、それを指定することで参照したい情報が一意に決まるものはパスに入れる
  • アクセストークンなど、利用者の認可が目的であるものはリソースとは無関係のため、クエリパラメータに入れる

省略可能かどうか

  • 省略すればデフォルトの値が利用される

ログインとOAuth 2.0

OAuth

https://oauth.net/2/

  • ユーザーがサービスを利用するときに、ユーザー登録機能をもつ別サービス(SNSなど)に登録している情報を利用して良いという許可を与えること
  • ユーザーがOAuthでのアクセスに成功すると、SNS側からアクセストークンが発行される

用語

英語 日本語訳
Authorization 権限付与, 権限
Grant 許可証, 承認
Credential 権威の証明証, 資格

Grant Type

リソースへのアクセスの承認フローは4つ定められている。

GrantType Purpose
Authorization Code Railsなどサーバサイドで多くの処理を行うウェブアプリケーション向け
Implicit スマートフォンアプリやJavascriptを用いたクライアントサイドで処理の多くを行うアプリケーション向け
Resource Owner Password Credentials サーバーサイド(サイトB)を利用しないアプリケーション向け(直接ユーザーからパスワードを受け取ってサーバAからアクセストークンを受け取る)
Client Credentials ユーザー単位での認可を行わないアプリケーション向け(社内のAPIサーバー等信頼できるクライアントからOAuthするとき)
  • FacebookやTwitterが提供しているようなのは、Authorization CodeとImplicit
  • もし自分で作るAPIでOAuthを提供するのであれば、GrantTypeの実装が必要

TIPS: O'REILLYは↑といっているが、スマートフォンアプリはResource Owner Password Credentialsらしい。 http://qiita.com/awakia/items/66975de18ba25f18a961

OAuth利用のエンドポイント

/oauth2/tokenあたりが妥当。

  • OAuth2.0を使っているのが明確
  • RFC 6749のサンプルとも類似性がある(らしいが見当たらなかった)

Resource Owner Password Credentialsの認証を行う

以下のデータをapplication/x-www-form-urlencoded、UTF-8で送る。

Key Description
grant_type passwordという文字列で、Resource Owner Password Credentialsの認証であることを表す
username ログインするユーザー名
password ログインするパスワード
scope アクセスのスコープを指定する(省略可能)

TIPS: scopeは、FacebookならE-mailを取得するemailや友達一覧を取得するread_friendlistsなど。

クライアントのリクエストの例
POST /v1/oauth2/token HTTP/1.1
Host: api.example.com
Authorization: Basic Y2xpzW5021kOmNsaWVudF9zZWNyZXQ
Content-Type: application/x-www-form-urlencoded

grant-type=password&username=mafmoff&password=abc&scope=api

Authorizationヘッダーは、クライアント認証と呼ばれ、アクセスしようとしているサービスやクライアントアプリケーションが何であるかを特定するための情報。 FacebookやTwitterなどにアプリケーションを登録すると発行されるClient IDとClient Secretを、Basic認証の形式で、Base64変換したものが入っている。

TIPS: Client IDとClient Secretの利用は任意だが、利用することで、アプリケーションごとにAPIのアクセス数を制限したり、ブロックしたりすることができる。

レスポンスの例
HTTP/1.1 200 OK
// 略

{
"access_token": "b77yz37w7kzy7cffuda6zz91",
"token_type": "bearer",
"expires_in": 2629743,
"refresh_token": "tGzx3JOkF0xF3Qx2TlKWIA"
}
  • token_type"bearer"はRFC 6750で定義されているOAuth 2.0のトークン形式
  • access_tokenの値の送付により、今後Client IDとClient Secretを利用せず、APIにアクセスできる
  • refresh_tokenは、アクセストークンを再発行してもらうためのトークン(返さないことも可能)
bearerトークンの送信方法は3つ
  • リクエストヘッダに入れる方法
  • リクエストボディに入れる方法
  • URIにクエリパラメータとして入れる方法

アクセストークンの有効期限と更新

  • expires_inは「あと何秒で通行期限を迎えるか」
  • 有効期限が切れると、サーバはinvalid_tokenというエラーをステータスコード401で返す
Unauthorized時のレスポンスの例
HTTP/1.1 401 Unauthorized
// 略

{
"error": "invalid_token"
}
  • このJSON形式はRFC 6749で、invalid_tokenはRFC 6750で定義されている

自分の情報へのエイリアス

以下あたりが妥当。

  • users/me
  • users/self

users/:idusers/meでは処理が必然的に分岐するので、他人の情報が丸見えになるバグの混入を避けられる。


ホスト名とエンドポイントの共通部分

ホスト名にAPIを入れるのが主流

サービス エンドポイントの共通部分
Twitter api.twitter.com/1.1
NetFlix api-public.netflix.com
LinkedIn api.linkedin.com/v1
  • パスに入れるとURIが冗長になる
  • ホスト名を分けると、DNSレベルで分割できるので管理しやすい

example.comというサービスの提供するAPIのホスト名はapi.example.comが適切。


HATEOAS(hypermedia as the enfine of application state)

  • APIの返すデータの中に、次に行う行動、取得するデータなどのURIを含める

HATEOASのレスポンス例

{
  "friends": [
    { "name": "Saeed",
      "link": {
        "uri": "https://api.example.com/v1/users/12345",
        "rel": "user/detail"
      }
    },
    { "name": "Jack",
      "link": {
        "uri": "https://api.example.com/v1/users/12346",
        "rel": "user/detail"
      }
    }
  ]
}

すばらしいREST API

Martin Fowlerさんは言っている。

REST LEVEL What to do
0 HTTPを使っている
1 リソースの概念の導入
2 HTTPの動詞(GET/POST/PUT/DELETEなど)の導入
3 HATEOASの概念の導入

REST LEVEL 3 API

メリット

  • クライアントは入口となるのエンドポイントだけ知っていれば、その他のURIは知る必要がない
  • URIの変更がしやすいので、URIをHackableにする必要がなくなる
  • URIの変更に応じたクライアント側の変更が不要になり、保守が容易になる
  • エンドポイントがわかりにくくても良いので、アクセスしてほしくないURIを想像しにくくできる

選定基準

向いているもの。

  • スマートフォンアプリなど、変更から配布に時間がかかるもの
  • SSDKs、特定のクライアントのみで使われるようなAPI

時期尚早


レスポンスデータの設計

データフォーマット

JSONがデファクトスタンダード。

TIPS: デファクトスタンダードとは「事実上の標準」という意味。

データフォーマットの指定方法

  • クエリパラメータに指定する(POSTの場合はフォームデータやボディを含む)
  • URIの最後に.json.xmlを付けて指定する
  • Acceptというリクエストヘッダを使う

TIPS: お行儀が良いお作法はリクエストヘッダ利用だが、敷居が高く、クエリパラメータを使う方法が最も普及している。

JSONP(JSON with padding)

JSONにそれをラップするJavaScript(padding)を付け加えたもの。

callback({"id":123, "name":"Saeed"})

TIPS: paddingは「余計なもの」を意味しているので、JavaScriptのコードである必要はない。

データの内部構造の考え方

  • APIのアクセス回数がなるべく減るようにすること
  • APIのユースケースをよく考えること

APIのアクセス回数がなるべく減るようにすること

  • HTTPのオーバーヘッドが上がり、アプリケーションの速度低下を招くことを避ける
  • アプリケーションの特性を踏まえた上で、クライアントが使いやすい構造を検討する

TIPS: 1つの作業を完結するために複数回のアクセスを必要とするAPIの設計は、Chatty(おしゃべりな)APIと呼ばれる。ChattyAPIはネットワークのトラフィックを増加させ、クライアントの処理の手間を増やすめんどうな仕様のAPI。

レスポンスの内容を選べるようにする

  • クエリパラメータを使って、取得したい情報を指定する

TIPS: ある程度の情報のまとまりを指定する方法に「レスポンスグループ」というセットを使うこともある(AmazonのAPI)

エンベロープ

以下のようなメタデータも含む形で、すべてのAPIが同じデータ構造を返すために実際のデータをくるむための構造。

{
  "header": {
    "status":"success",
    "errorCode":0,
  },
  "response": {
    // データ
  }
}

便利に見えるエンベロープ

  • データ形式が共通になるので、クライアントサイドで抽象化しやすい
  • JSONPを使うケースに向いている(ステータスコードやレスポンスヘッダにアクセスできないため)

だが、エンベロープは不要

O'REILLY本に言わせると、

  • HTTPを利用している場合、HTTPがすでにエンベロープの役割をしている
  • HTTPのステータスコードとエンベロープないのstatusの不一致などが起きやすい
  • メタ情報はHTTPヘッダに書けば良く、レスポンスボディ内の無駄が省ける

データはフラットにするべきか

「なるべくフラットが良いけれど、階層構造をもった方がわかりやすい場合もあるよね」

by Google JSON Style Guide

その階層化が本当に必要なものかどうかはよく考える。

NGパターン

{
  "id":1234,
  "name":"Hoge Fuga",
  "profile": {
    "birthday":1231,
    "gender":"male",
    "language": ["ja", "en"]
  }
}

profileというカテゴリは、これがなくても見た目的にもコードの処理上でも違いはなく、JSONのデータサイズが大きくなるだけなので、不要。

JSONのトップレベルには、オブジェクト vs 配列

TIPS: JSONのオブジェクトは順序が考慮されない。

JSONのトップレベルがオブジェクトであれば、

  • レスポンスデータが何を示しているのかがわかりやすくなる
  • レスポンスデータをオブジェクトに統一することができる
  • セキュリティ上のリスクを避けることができる
レスポンスデータが何を示しているのかがわかりやすくなる
  • 例えばfriendsというキーが付いていれば、データが友人情報であることがひと目でわかる
レスポンスデータをオブジェクトに統一することができる
  • クライアント側の受け取り処理が共通化できる
セキュリティ上のリスクを避けることができる
  • トップレベルが配列だと、JSONインジェクションの脆弱性に対するリスクが大きくなる

TIPS: JSONインジェクションとは、script要素を利用してJSONファイルを読み込むことによって、ブラウザに他サービスのAPIが提供するJSONファイルを読み込ませ、その内容を不正に入手する方法。

配列の件数や、つづきの有無をどう返すか

たとえば、hasNextキーで返す

  • 20件返すためには最大21件の取得を行ってみて、21件めが取得できれば"hasNext": trueとする方法

TIPS: ここで、Google*のAPIがやっているように次ページのURIなどを併せて返すとすると、HATEOASっぽくなる。

各データのフォーマット

フィールドの命名規則

  • 多くのAPIで同じ意味に利用されている一般的な単語を用いる
  • なるべく少ない単語数で表現する
  • 複数の単語を連結する場合、その連結方法はAPI全体を通して統一する
  • 省略形はなるべく使わない
  • 単数系/複数形に気をつける

TIPS: Google JSON Style Guideでは、配列の場合は複数形、それ以外は単数系にするというルールがある。

性別データ

  • genderは「社会的・文化的性別」、sexは「生物学的な性別」
  • genderの場合は、性別の種類が増えることも考慮してフォーマットは"gender": "male"のように文字列が良い
  • 医療系サービスはsex、それ以外はgenderが良い

日付のフォーマット

Format Example
RFC 822 Sun, 06 Nov 1994 08:49:37 GTM
RFC 850 Sunday, 06-Nov-94 08:49:37 GTM
ANSI Cのasctime()形式 Sun Nov 6 08:49:37 1994
RFC 3339 2015-10-12T11:30:22+09:00
Unixタイムスタンプ(epoch秒) 1396821803

RFC 3339

  • LSUDsなAPIに向いている
  • W3C-DTFという日付形式の年から秒までをすべて省略せずに含めている
  • JanFriなど特定の言語に依存した表記を含まず、曜日の表記を含まないので、冗長さが排除されている
  • HTTPヘッダに用いるHTTP時間においてはタイムゾーン+00:00を使うのがわかりやすい

Unixタイムスタンプ(epoch秒)

  • 1970年1月1日0時0分0秒(UTC:協定世界時)からの経過時間を秒数で表したもの
  • データ形式としては単なる数値なので、比較や保持が容易でサイズが小さいので、SSKDsではこちらが使いやすい場合もある

大きな整数を扱うとき

浮動小数などの扱いで、誤差が出てしまうことがある。

  • IDなど大きな数字を扱う場合、文字列として返すことで回避できる

エラー

ステータスコード

エラーは、レスポンスボディで返すだけでなく、まずは適切なステータスコードを返すこと。

ステータスコード 意味
100番台 情報
200番台 成功
300番台 リダイレクト
400番台 クライアントサイドに起因するエラー
500番台 サーバーサイドに起因するエラー

エラーの詳細を返す方法

以下の2つ。

  • HTTPのレスポンスヘッダに入れて返す方法
  • レスポンスボディで返す方法

HTTPのレスポンスヘッダに入れて返す方法

独自に定義したヘッダ項目を用意して、情報を入れる。

X-MYNAME-ERROR-CODE: 2013
X-MYNAME-ERROR-MESSAGE: Bad authentication token
X-MYNAME-ERROR-INFO: http://docs.example.com/api/v1/authentication

レスポンスボディで返す方法

クライアント側からみたときの利便性を考えるとこちらが良い。

{
  "error": {
    "code": 2013,
    "message": "Bad authentication token",
    "info": "http://docs.example.com/api/v1/authentication"
  }
}

TIPS: 複数のエラーが同時に発生した場合を考慮して、Twitterはエラーが配列で返るようになっている。

エラーの詳細情報の内容

  • ステータスコードと区別するために、4桁などにする
  • 1000番台は汎用エラー、2000番台はユーザー情報のエラーというようにカテゴリごとに分ける
  • エラーメッセージは、エンドユーザー向け、開発者向けで分けても良い

メンテナンス

  • スケジュールされたメンテナンスであればRetry-AfterというHTTPヘッダを用いて、終了日時を示すと親切

**TIPS: **メンテナンスの時間は長めに見積もっておくこと。

### 敢えてあいまいなエラーを返す

  • SNSのブロック機能では、エラー403だとトラブルを招くかもしれないので、404をわざと返す
  • ログインAPIなどでは、セキュリティ上どのフィールドがNGなのかがわからない方が良いので、あいまいにする

HTTP

主なステータスコード一覧

ステータスコード 名前 説明
200 OK リクエストは成功した
201 Created リクエストが成功し、新しいリソースが作られた
202 Accepted リクエストは成功した
204 No Content コンテンツなし
300 Multiple Choices 複数のリソースが存在する
301 Moved Permanently リソースは恒久的に移動した
302 Found リクエストしたリソースは一時的に移動している
303 See Other 他を参照
304 Not Modified 前回から更新されていない
307 Temporary Redirect リクエストしたリソースは一時的に移動している
400 Bad Request リクエストが正しくない
401 Unauthorized 認証が必要
403 Forbidden アクセスが禁止されている
404 Not Found 指定したリソースが見つからない
405 Method Not Allowed 指定されたメソッドは使うことができない
406 Not Acceptable Accept関連のヘッダに受理できない内容が含まれている
408 Request Timeout リクエストが時間以内に完了しなかった
409 Conflict リソースが矛盾した
410 Gone 指定したリソースは消滅した
413 Request Entity Too Large リクエストボディが大きすぎる
414 Request-URI Too Long リクエストされたURIが長すぎる
415 Unsupported Media Type サポートしていないメディアタイプが指定された
429 Too Many Requests リクエスト回数が多すぎる
500 Internal Server Error サーバー側でエラーが発生した
503 Service Unavailable サーバーが一時的に停止している

200番台 成功

201 Created

  • リクエストメソッドでPOSTが使われたとき
  • サーバ上に新しいファイルが作成されたり、データベースのテーブルに項目が追加されたとき

202 Accepted

  • リクエスト処理が非同期で行われ、処理は受け付けたが完了はしていない状態
  • 「処理は開始したけど、終わっていませんよ」という通知

204 No Content

  • レスポンスが空のとき
  • DELETEメソッドでデータの削除を行ったとき
  • PUTやPATCHメソッドでのデータの更新にも使われる(O'REILLYの筆者は勧めていない)

TIPS: 「コンテンツが空」というだけではわかりにくいので、DELETEで削除したデータそのものを返すべきだという主張もある。

300番台 追加で処理が必要

主にリダイレクトに関する。 リダイレクトの場合、Locationというレスポンスヘッダにリダイレクト先の新しいURIが含まれる。

HTTP/1.1 302 Not Found
Date: Sat, 23 Nov 2013 12:24:25 GMT
Content-Type: text/plain
Content-Length: 41
Connection: keep-alive
Location: http://example.com

302 Not Found

300 Multiple Choices

  • ファイルストレージ系のサービスで、指定したキーに対して複数のデータが存在すると返るときがある

304 Not Modified

  • クライアント側でそれまでのデータのキャッシュを行い、キャッシュの情報を返してくれたとき
  • レスポンスボディは空になる

400番台 クライアントのリクエストに問題がある

400 Bad Request

  • その他の400番台でのエラーでは表すことができないエラー
  • 送られてきたパラメータに間違いがあって処理できないとき

401 Unauthorized

  • 認証エラー
  • 「あなたが誰だかわからないよ」

403 Forbidden

  • 認可エラー
  • 「あなたは誰だかはわかったけど、この操作はあなたには許可されていないよ」

404 Not Found

  • 「アクセスしようとしたデータは存在していないよ」

405 Method Not Allowed

  • エンドポイントは存在しているがメソッドが許可されていない
  • たとえばGETのみでアクセス可能なAPIにPOSTでアクセスしたとき

406 Not Acceptable

  • 指定された形式がサポート外のとき
  • たとえばJSONXMLしか対応していないのに、YAMLを指定されたとき

408 Request Timeout

  • リクエストをクライアントがサーバに送るのに時間がかかりすぎてサーバ側でタイムアウトを起こしたとき

409 Conflict

  • リソース競合が発生したとき
  • すでにそのリソースが存在するとき
  • たとえばIDなどのユニークなキーを指定して、データを登録するAPIで、IDが重複しているとき

410 `Gone

  • 404と似ているが、410はかつて存在したが、今はもうリソースが存在しないとき
  • データを削除したという情報を保持する必要がある

TIPS: ユーザーからもわかってしまうので、個人情報保護などの観点から問題を指摘されるかも。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment