#前置き
あの有名なドラゴン◯ールとは一切関係がありません
#WebAPIって何?
孫コ空「おっす、おら孫コ空!
この間海王様からWebAPIっちゅーの聞いたんだけど、おらにはさっぱりだ。」
ふるま「あら、ソンくん。WebAPIが分からないの? それは、私の得意分野じゃない。教えてあげるわ」
孫コ空「おー本当か!さすがふるまだな。早速教えてくれ!」
ふるま「いいわ。まずAPIについて理解してる?」
孫コ空「ぜんぜんだぞ!」
ふるま「APIっていうのはApplication Programming Interface
の略で
簡単にいうと『中身の動作までは知らないけど、どんな機能かを知ってれば外部からでも使える仕様』のこと」
孫コ空「それのWeb版がWebAPIってことか」
ふるま「まあそうね。もう少しいうと『HTTPプロトコルを使ってネットワーク越しに呼び出すAPI』
とかになるけど、簡単にいうとURIにアクセスしてデータを取得したり、作成することができるの。」
孫コ空「最近おらが使ってるサービスでTwitterと連携したら
Twitterのタイムラインが見れたけど、それもWebAPIになるのか?」
ふるま「そう!TwitterはWebAPIでURIを公開してるから、
そのサービスではURIから情報を取得して、ソンくんにデータを表示しているの。」
孫コ空「そういうことか!でもAPIを公開する意味ってあるのか?」
##WebAPIを公開する意味
ふるま「いい質問だね!さっき例に出たTwitterがそうだけど、2006年からほとんどの機能をAPIで公開してたの。
だからTwitterに関連するサービスがたくさん出たんだけど出ることで、Twitterに付加価値が生まれるの。」
孫コ空「確かに、botとかツイート分析とかたくさんあったぞ!
Mr.タサンはツイートから性格分析するために、Twitter始めたって言ってたぞ」
ふるま「そういうサービスが出れば出るほど、Twitterは付加価値になるからお得なのよ。」
孫コ空「すげー効果ありそうだな!他にもメリットはあるのか?」
ふるま「他にも、自分たちでは手が回らなかったり、思いつかなかった機能を作ってくれる時があるの。
実際に、関連するサービスで作られた機能を、大元のサービスが取り入れる事もあるわ。」
孫コ空「なんか実際に作ってみたくなってきたぞ!」
##REST APIについて
ふるま「少し寄り道だけどREST API
って聞いたことある?」
孫コ空「なんか聞いたことあるぞ!」
ふるま「REST
の言葉は、2000年のRoy Fieldingさんの博士論文が始まりなの。
だけどRESTの意味は、『論文のRESTアーキテクチャの意味』と、
『HTTPでアクセスできて、データ形式をJSONかXMLで返すAPIの意味』の2種類で使われるの。」
孫コ空「なんだかややこしいぞ。」
ふるま「ごめん笑。じゃあ早速だけどWebAPIの設計について話していくわ。」
孫コ空「ありがてぇーぞ!おらにも分かるようにしてくれると助かるぞ!」
#WebAPI設計
##WebAPIエンドポイント
ふるま「それじゃあ、WebAPIを作る時に注意しなきゃいけないことがあるの。」
孫コ空「使いやすくするってことか!」
ふるま「そう!そこでまずAPIのURI、つまりエンドポイントを分かりやすくする必要があるの」
孫コ空「例えばどいうことだ?」
ふるま「例えば、友達一覧を取得するAPIだったら、どれがいいと思う?」
1.https://api.example.com/friends
2.https://api.example.com/service/api/friends
3.https://api.example.com/f
4.https://api.example.com/Friends/list
孫コ空「これは1番が使いたくなるぞ!」
ふるま「そうよね!
2番はapiが2回入って長いし、3番はエンドポイントだけ見ても理解できない、
4番はパッと見いいけどFが大文字なのが気になるわよね」
孫コ空「そうか!使う立場になって考えることが大事ってことなんだな!」
ふるま「さすがそういうこと!それじゃあ次はHTTPメソッドにいくわね」
孫コ空「おらちょっと疲れてきたぞ!」
ふるま「いつももっと体動かしてるじゃない」
##HTTPメソッド
ふるま「それじゃあ次はHTTPメソッドについてね。
HTMLのformでmethod属性に指定するのは知ってるかしら。
<form action="http://example.com" method="get">
HTTPメソッドはHTTPリクエストヘッダの先頭行の最初につけられてサーバに送信されるの。」
GET /v1/friends HTTP/1.1
Host: api.example.com
孫コ空「前にHTMLやった時にgetとかpostって付けたぞ!」
ふるま「それならよかったわ。そのHTTPメソッドには意味があって
URIが操作するリソース
でHTTPメソッドがどうするのか
って捉えるといいわ。」
孫コ空「https://api.example.com/friends
でGETメソッド
だと
友達っていうリソースを取得するってことだな!」
ふるま「そうだわ。getやpost以外にもHTTPメソッドはあるの」
メソッド名 | 意味 |
---|---|
GET | リソースを取得 |
POST | リソースを新規登録 |
PUT | 既にあるリソースを更新 |
DELETE | リソースを削除 |
PATCH | リソースの一部を更新 |
孫コ空「こんなにあるのか!」
ふるま「一応まだ他にもあるけど、この辺が主要かしら。それじゃあ一つずつ簡単に話すわ」
###GETメソッド
ふるま「URIで指定された『リソースの取得』を表すわ。
もちろんAPIにもよるけど、
https://api.example.com/friends
が友達の一覧取得で
https://api.example.com/friends/123
でIDが123の友達の詳細取得
なんてパターンもあるわ」
孫コ空「一覧の取得と詳細の取得ていうのがあるのか。
IDっていうのは、リソースを指定するってことでいいんだよな?」
ふるま「そうだわ。あと、GETメソッドでデータを更新するのは、絶対にダメだからね」
孫コ空「分かったぞ!」
###POSTメソッド
ふるま「POSTメソッドは、URIに属する新しいリソースを送信して、新規作成するメソッド。
ただHTML4.0のformがGET
とPOST
しか指定できないから、更新か削除でもPOSTメソッドで処理している場合もあるわ。」
孫コ空「どっちにするのがいいんだ?」
ふるま「WebAPIは、POSTは新規作成のみにするのがベターだわ。」
###PUTメソッド
ふるま「PUTメソッドは、URIでリソースを指定して更新するわ。
URIは例えばこんな風に
https://api.example.com/friends/123
って123でリソースを指定して更新をするわ。」
孫コ空「なんかさっきのGETメソッドの詳細取得みたいだな。」
###DELETEメソッド
ふるま「DELETEメソッドは、URIでリソースを指定して削除するわ。」
###PATCHメソッド
ふるま「PATCHメソッドは、URIでリソースを指定して一部更新するわ。」
孫コ空「PUTメソッドとの違いはなんだ?」
ふるま「PUTメソッドは指定したリソースを一気に更新するんだけど、
PATCHメソッドは、差異がある部分だけど更新するから、
リソース自体が10MBとかサイズが大きいとPUTメソッドより、PATCHメソッドで差異だけ更新する方が効率がいいの。」
孫コ空「確かにそれはありそうだな!」
##検索とクエリパラメータ
ふるま「それじゃあ中盤ね。検索とクエリパラメータについてだわ」
孫コ空「まだ中盤かぁ、おら腹減ったぞ。」
ふるま「後でUberEats頼むから笑」
孫コ空「よし、おら元気出てきたぞ!」
ふるま「さっきやったけどGETメソッドで一覧取得をやったけど、
友達の数が2万人いて、それを全て取得しようとしたら大変じゃない?」
孫コ空「そんなにたくさん取得してもほとんど使わないぞ!」
ふるま「そうよね、そんな時にリソースの絞り込みをするんだけど
そこで条件を指定する時に、クエリパラメータを使うの。
例えば、https://api.example.com/friends?limit=20&offset=10
で
limit=20とoffset=10に指定してるの。」
孫コ空「見たことあるぞ!でもどういう意味だ?」
ふるま「APIによって意味は様々だけど、まずはページネーションからね。」
###ページネーション
ふるま「ページネーションっていうのは、データの取得数と取得位置を指定するの。
例えば、さっきのだと『limit=20
とoffset=10
でデータ一覧の10番目から20個を取得する』
みたいな意味になるの。」
孫コ空「そういうことか。確かにそれなら友達が2万人いても平気だぞ!
limit
とoffset
っていうの名前は決まっているのか?」
ふるま「それはAPIによって様々だわ。よく使われるのは、
取得数にlimit
と取得位置にoffset
,
取得数にcount
と取得位置にcursor
,
取得数にper_page
と取得位置にpage
,とかになるかしら。」
孫コ空「どれを使おうか迷うぞ」
ふるま「ちなみにoffset
とpage
の意味が違うから注意ね。
offset
はアイテム数だけど、page
はper_page
単位で1ページ、2ページなるからね。
例えば11アイテム目からを指定する場合はこんな感じになるの。」
・per_page=5&page=3
・limit=5&offset=10
孫コ空「per_page
の指定が1ページあたり5件ってことでpage
で3ページ目からっていうことと、
limit
が5件取得ってことで、offset
が10件目からってことか?」
ふるま「そう!offset
が10件目?って思ったかもしれないけど、offsetは0からスタートするから問題ないの。」
孫コ空「そういうことか!limit
とoffset
の方が使いやすそうだぞ」
ふるま「好みもあるけど、私もlimitとoffsetの方が好きだわ」
###絞り込み検索
ふるま「それじゃあ、次は絞り込み検索の話に移るわね。
ページネーションだけじゃなくて、色んなパターンで絞り込みたい時があると思うの。」
孫コ空「確かに、名前とかメールアドレスとか複数の想定があるぞ!」
ふるま「そういう時は大体。クエリパラメータの名前には要素名、値には絞りこむ値を指定するの。
例えば、こんな感じになるわ」
https://api.example.com/friends?first-name=sita&last-name=Be
孫コ空「そうか!苗字と名前で検索してるっちゅーことか!」
ふるま「そう。ただ条件が1つだったり、全文検索の場合はq
が使われることが多いわ。」
https://api.example.com/friends?q=Besita
孫コ空「q
ってqueryの略か?」
ふるま「そういうこと!」
孫コ空「理解できたぞ!」
#レスポンスの設計
ふるま「それじゃあ、リクエストについてやったから今度はレスポンスについてね。」
孫コ空「海王様より詳しくやってる気がするぞ!」
ふるま「知ってて損はないわよ笑
レスポンスだけどまずデータフォーマットは基本的にはJSON
にするって考えて問題ないわ。」
孫コ空「そうなのか?おらXML
とか聞いたことあるぞ!」
ふるま「前はXML
が主流だったんだけど
今ではJSON
がデファクトスタンダードになってるから、必要があればXML
にも対応するって感じになるわね。」
孫コ空「じゃあ、おらはとりあえずJSON
で作るぞ!」
ふるま「それがいいわ!」
##データ構造
ふるま「エンドポイントの時もそうだったけど、レスポンスも使いやすいように返さないといけないの。
例えば、この例でどっちが使いやすいと思う?」
{
"friends":[
123,
234,
345
]
}
{
"friends":[
{
"id":123,
"name":"Besita",
"icon":"~~.png"
},
{
"id":234,
"name":"Dorankusu",
"icon":"~~.png"
}
]
}
孫コ空「①番はIDなんだろうけど、またリクエストしないといけなくなりそうだから
②番の方が良さそうだぞ!」
ふるま「そう!友達一覧取得する時は普通に名前とかも当然欲しいよね。
だから①だとIDからまた取得することになって、ユーザも大変だしサーバの負荷も上がるから、いいことないの。」
孫コ空「でもどこまでレスポンスすればいいのか、難しいぞ」
ふるま「そうね、そういう時はユーザが選べるようにすれば問題ないわ」
##必要な分をレスポンスできるようにする
ふるま「一度にたくさんのデータをレスポンスすれば楽だけど、
ユーザは必要じゃないデータをレスポンスされても、ダウンロードにも時間がかかって不便よね。
だからユーザ自身で選べるようにするのがいいわ。」
孫コ空「確かに、選べた方が嬉しいぞ!」
ふるま「だからユーザが選べるようにクエリパラメータで指定することができるようにするの。」
https://api.example/friends/123?fields=name,age
孫コ空「なるほど!fieldsで必要なデータだけになるのか!」
ふるま「そう!fields
を指定しなかったら、全てを返すとかにしておけば
ユーザにも使いやすくなるわよね」
孫コ空「めっちゃ便利だな!」
##ステータスコード
ふるま「それじゃあ、HTTPに関わってくるところだけど、ステータスコードもやっちゃうわ!」
孫コ空「ステータスコードなら少しわかるぞ!404
とか500
とかのやつで合ってるか?」
ふるま「そう!リクエストがサーバによってきちんと処理されたのかを表すステータスのこと。
他にも種類がたくさんあるから、表にするわ」
ステータスコード | 意味 |
---|---|
100番台 | 情報 |
200番台 | 成功 |
300番台 | リダイレクト |
400番台 | クライアントが原因のエラー |
500番台 | サーバサイドが原因のエラー |
ステータスコード | 名前 | 意味 |
---|---|---|
200 | OK | リクエストは成功した |
201 | Created | リクエストが成功し、新リソースを作成した |
202 | Accepted | リクエストは成功した |
204 | No Content | コンテンツがない |
301 | Moved Permanently | リソースは移動している |
302 | Found | リソースは一時的に移動している |
400 | Bad Request | リクエストが不正である |
401 | Unauthorized | 認証が必要である |
403 | Forbidden | リクエストが禁止されている |
404 | Not Found | 指定したリソースが見つからない |
405 | Method Not Allowed | 指定したHTTPメソッドは、使用できない |
408 | Request Timeout | リクエストが時間内に終了しなかった |
429 | Too Many Requests | リクエスト回数が多すぎる |
500 | Internal Server Error | サーバ側でエラーが発生した |
529 | Service Unavailable | サーバが停止している |
孫コ空「こんなにあるのか!おら覚えらんねーぞ!」
ふるま「覚えなくても都度調べれば大丈夫よ!まだ他にもあるからね」
孫コ空「まだあんのか!すげー量だな!」
ふるま「簡単に補足するわね。」
###200番台 成功
ふるま「200は、一般的よね。
201は、POSTメソッドが成功してリソースが新規作成されたら返されるものね。
202は、リクエストが非同期で実行されて、処理は受け付けたけど完了はしていないの時に使われるわ。
204は、DELETEメソッドでリソースが削除された時に使われるの。」
孫コ空「なるほど!」
###300番台 追加で処理が必要
ふるま「300番台は、リダイレクトが一般的よね。
URIのアクセスに対して、目的のアクセスは別のURIに変わっていることを伝えるために使用するステータスコード。
ただ、これはWebAPIで使うことはおすすめしないわ。
ユーザがリダイレクトの対応をしてないと、クライアントが動かなくなったりするからね。」
孫こ空「リダイレクトは本当に必要な時にだけって覚えておくぞ!」
ふるま「問題ないわ!」
###400番台 クライアントのリクエストが原因
ふるま「これは、クライアントのリクエストに原因がある番号ね。
401は、認証エラーでリクエストした人を認識できない時だわ。
403は、認可エラーでリクエストした人にはアクセス許可されていない時。
あとは、なんとなく理解できるかしら。ちなみに
400は、他の400番台で表せない時に使う『その他』になるの。
クエリパラメータに問題がある時なんかに使うわよ。」
孫コ空「401と403が混ざりそうだぞ」
ふるま「その時は、調べたら問題ないわよ」
孫コ空「都度調べるっちゅーことだな!」
###500番台 サーバに原因
ふるま「これは、開発者はよく見るかしら
サーバ側のバグが原因でエラーが発生して処理が止まっているから、きちんと監視することが大切ね。
503は、システムメンテナンスだったり、サーバが過負荷でサーバが止まっている状態のこと」
孫コ空「500がでた時は、通知がいくようにしてるぞ!」
ふるま「さすがだわ!」
##エラーの内容をレスポンスに含める
ふるま「ステータスコードをやって、400番台でユーザにクライアントの原因を伝えることができることがわかったわね。
でも、404のNot Foundをレスポンスする時に『何がNot Foundなのか』も伝えるべきなの。」
孫コ空「確かに、おらだったら404だけ返されても何がNot Foundなのか分からないぞ」
ふるま「そう!だから、内容を教えてあげる必要があるの。
今回は例にTwitterとGithubを使うわ」
{
"errors":[
{
"message":"Bad Authentication data",
"code":215
}
]
}
{
"message":"Not Found",
"documentation_url":"https://developer.github.com/v3"
}
ふるま「ちなみに、Twitterは配列になっていてエラーが複数合った場合は
複数レスポンスしてくれるの、開発者に取ってはありがたいわよね。」
孫コ空「親切だな!! おらも複数レスポンスすっぞ!」
#バージョン管理
ふるま「APIを公開していると、そのAPIをいきなり変更するとユーザは困るでしょ。
でもAPIを、改善していきたいっていう時には、新しい改善したAPIは別のエンドポイントをするの。」
孫コ空「それなら元々使ってるユーザは困らないそうだぞ!」
ふるま「そう!こうやってやるの」
https://api.example.com/v1/friends
ふるま「APIのパスの先頭にv1
っていうバージョン1っていうのを示しておくの。」
孫コ空「そうか!それじゃあ更新したらv2
に上げていけばいいのか!」
ふるま「そうよ!ただ後方互換性を保てる時は、できる限りバージョンを上げずにしない方が
APIの管理が増えないから、互換性を保てない時にあげるべきだわ。」
孫コ空「確かに、増えすぎると後で大変な気がするぞ!
でもAPIのバージョンを上げた時は、古い方はいつまでサポートすればいいんだ?
ずっとサポートしてるのもおら大変だぞ」
ふるま「いい質問ね!ただそれは明確な決まりはないわ。
だけど古いほうのAPIを使っている人に移行する期間を設ける必要があるわ。
いきなり終了するとユーザは困るからね。」
ふるま「Twitterの場合だと6ヶ月以内に終了するってアナウンスをしてから停止してるわ。
最低でも6ヶ月は、設けると安心だと思うわ。」
孫コ空「半年か!時と精神の部屋だったら、半日だ!」
ふるま「そうなのね笑
あとは、事前にAPIのサポート期間をドキュメントとかに記載しておくっていうのもありね。」
孫コ空「事前に伝えておけば、伝わってないっていうことは減りそうだぞ」
ふるま「APIの提供が終了したら、エラーメッセージで提供は終了した旨を伝えると
さらに親切ね」
孫コ空「おらもそうするぞ!」
#終わり
ふるま「じゃあとりあえず、これで終わり!」
孫コ空「おー!やっと終わったか!おらもう腹減っちまったぞ」
ふるま「好きなだけUberEatsで頼んでいいわよ笑」
孫コ空「どれにしよっかなー」
#参考
孫コ空「この本はすっげー分かりやすいから、おすすめだぞ!」
Web API: The Good Parts