1.Web APIの基礎知識
1.1. Web APIの基礎知識
1.1.1. APIとは
API(Application Programming Interface)はプログラムの機能の一部を別のプログラム上で利用できるように共有する仕組み。
Web APIはHTTPプロトコル(httpやhttpsなど)のWeb技術を用いて実現されるAPIの一種。 言い換えると、ある URI にアクセスすることで、サーバ側の情報を書き換えたり、サーバ側に置かれた情報を取得したりできる Web システムで、プログラムからアクセスしてそのデータを機械的に利用するためのものである。
1.1.2. 様々なAPIの実装
開発者が Web API を設計しなければならない機会は以下のようなものがある。
- 公開している Web サービスのデータや機能のAPI公開
- 他のページに貼り付けるウィジェットの公開
- モダンなWebアプリケーションの構築
- スマートフォンアプリケーションの開発
- ソーシャルゲームの開発
- 社内システムの連携
1.1.3. Web APIの種類
XML-RPC
データ形式にXMLを利用しインターネット上でリモートプロシージャコール(遠隔手続き呼び出し)を行うタイプのAPIである。
返り値はXML形式で返ってくる。
SOAP
2000年代前半まで主流だったWeb API。 SOAPのようなXMLベースで仕様が複雑なものは近年ではあまり使われなくなってきている。
REST
最近では主流なWeb API。Web API = RESTほどなまで注目されている。
1.1.4. Web APIをきれいに設計するには
APIをきれいに設計しなければならない理由は以下の通り。
設計の美しいWeb APIは使いやすい
APIを作り公開する場合、そのAPIを利用するのは自分ではないケースが多い。APIを設計するからには多くの人に利用してもらいたいので、そのためにもAPIを利用する側にはストレスなく使ってもらえるよう、使いやすさを意識する必要がある。
設計の美しいWeb APIは変更しやすい
Webサービスやシステムはどんどん進化していく。公開した当時と同じ状態のまま2年も3年も運用が続けられるケースは少ない。進化していけばインターフェースであるAPIも変化を余儀なくされる。
ただ、APIは自分たちと関係ない第三者が使っている場合も多く、その場合いきなりAPIの仕様が変わってしまうと、そうした人たちの作ったシステムやサービスがいきなり動かなくなる、といったことも考えられる。こうした事態はAPIを提供する側としては避けなければならない。そのためにもAPIの変更をいかに利用者に影響なく変更できるかを意識する必要がある。
設計の美しいWeb APIは頑強である
Web APIはインターネットを通じて提供するため、誰でもアクセス可能になってしまう。 そのため、セキュリティの問題が必ず発生する。APIといえど、ウェブサイトと同じHTTPを利用している以上、ほぼ同等のセキュリティの問題を意識する必要がある。
1.2. エンドポイント設計とリクエスト形式
1.2.1. APIの機能設計とAPIエンドポイント
APIの機能設計
公開したAPIがどのように使われるのかユースケースをきちんと考えることが重要である。
APIエンドポイント
Web APIにおけるエンドポイントはAPIにアクセスするためのURI。
基本的にはURI が「リソース」を指すものであり、URIとHTTP メソッドの組み合わせで処理の内容を表すのが良い設計であるとされている。
1.2.2. APIエンドポイントの設計
覚えやすくどんな情報をもつURIなのかがひと目でわかるという原則に従い設計する。 設計のポイントは以下の通り。
短く入力しやすいURI
不要な情報が入っていたり、意味が重複していたりするURIは避けるべきである。
- ダメな設計
http://api.example.com/service/api/search
- 良い設計
http://api.example.com/search
人間が読んで理解しやすいURI
URIだけで何を目的としたものが理解できることが重要である。 また意味不明な略語や一般的に使用される英語以外をURIに用いるのは避けるべきである。
一般的にAPIで使われる単語を知るには、実際に他のAPIやProgrammableWebを参照する。 単語の複数形や過去形については間違いが混入しやすいので特に注意する。 慣れてる人にしか伝わらない省略表現をむやみに使うことは避けたほうが無難である。
大文字小文字が混在していないURI
標準的に選択されているのは小文字なので小文字で統一する方が好ましい。
大文字のURIで呼び出された場合には、単に 404 NotFound
で返すのが良い(小文字の URI にリダイレクトする必要ナシ)
改造しやすいURI
URIを修正して別のURI にするのが容易かどうか。 あるURIから他のURIを想像することが可能であれば、あまりドキュメントを読まなくても開発を進めることができAPI利用者の負担を軽減できる。
サーバアーキテクチャが反映されたURI
下記のようなエンドポイント設計はセキュリティ脆弱性を招く場合がある。
http://api.example.com/cgi-bin/get_user.php?user=100
上記の場合、API利用者に「PHPで書かれていてCGIとして動作しているんだろう」という情報を与えてしまう。 API利用者にどの言語やどのフレームワークなどでAPIが設計・構成されているかの情報を与える必要はない。
またアーキテクチャが反映されていると、攻撃者に対して脆弱性を突くためのヒントを与えてしまうことになる。
ルールが統一されたURI
例えば以下のようなルールが統一されていないAPIは避けるべきである。
http://api.example.com/friends?id=100
http://api.example.com/friend/100/message
エンドポイントを設計する中で注意すべき点
- 複数形の名詞を利用する(複数形の方が適切)
- 利用する単語に気をつける
- スペースエンコードを必要とする文字を使わない
- 単語をつなげる必要がある場合はハイフンを利用する
HTTPメソッドとエンドポイント
URIとメソッドは「操作するもの」と「操作方法」の関係にあると言える。
メソッド名 | 説明 |
---|---|
GET | リソースの取得 |
POST | リソースの登録(リソース名は指定しない) |
PUT | リソースの登録/更新(リソース名を指定する) |
DELETE | リソースの削除 |
PATCH | リソースの一部変更 |
HEAD | ソースのメタ情報の取得 |
POSTとPUTの使い分け
- POST と PUT の使い分けは、 URI の指定の仕方にある。
POST /photos
とすると、リソース名がサーバ側で割り振られて、GET /photos/25252
などの新しい URI がアクセス可能になる。- PUT は、
PUT /photos/25252
のように、使用者がリソースを指定する場合に使う。
PUTとPATCHの使い分け
- PUT はデータを完全に上書きしたい場合に使う。
- PATCH はデータの一部だけを更新したい場合に使う。
1.3. 検索とクエリパラメータ設計
1.3.1. ページネーション
ページネーションの仕組みを実現する方法は主に2つある。
- per_pageとpageで取得数と取得位置を指定
- limitとoffsetで取得数と取得位置を指定
相対位置でデータを取得する方法にはパフォーマンス上の問題がある。 (∵ offsetを使った場合はレコードを先頭から数えてしまう可能性があるから)
また更新頻度の高いデータにおいてデータに不整合が生じるという問題もある。 最初の20件を取得してから、次の20件を取得する間にデータの更新が入ってしまった場合、実際に取得したい情報と取得された情報にズレが生じてしまう。
offsetで相対位置を指定する代わりに、これまで取得した最後のデータのIDや時刻を記録しておいて、「このIDよりも前のもの」「このIDよりも後のもの」といった指定を行う方法もある(絶対位置による指定)。
1.3.2. 絞り込みのためのパラメータ
完全一致で検索する場合、以下のようなURIとするのが直感的である。
http://api.example.com/v1/users?name=ken
検索するフィールドがほぼ一つに決まる場合は q
というパラメータが使われる場合もある。
こちらは部分一致での検索というニュアンスが強くなる。
http://api.example.com/v1/users?q=ken
1.3.3. クエリパラメータとパスの使い分け
クエリパラメータに入れる情報はURI中のパスの中に入れることも設計上は可能である。
クライアントが指定する特定のパラメータをクエリパラメータに入れるか、パスに入れるかを決める際の基準は以下の通り。
- 一意なリソースを表すのに必要な情報かどうか
- 省略可能かどうか
1.4. ログインとOAuth2.0
1.4.1. OAuth
OAuthは基本的に広く第三者に公開されるAPIでデータや機能へのアクセス権限の許可を行う仕組み。
OAuthにより権限の許可を付与することで本来であれば利用することができない他サービスのリソースを連携してもらうことができる。
OAuthには 1.0 と 2.0 があり、2.0 は2012年10月にRFC6749として標準化されている。 OAuth 1.0を利用する理由は特にないため、実装する場合は2.0を利用するのが良い。
1.4.2. OAuth2.0の認証手順(Grand typeの設定)
名称 | 説明 |
---|---|
Authentication Code | サーバサイドで多くの処理を行うWebアプリケーション向け |
Implicit | スマートフォンアプリやJavaScriptを用いたクライアントサイドで多くの処理を行うアプリケーション向け |
Resource Owner Password Credentials | サーバサイド(サイトB)を利用しないアプリケーション向け |
Client Credentials | ユーザ単位での認可を行わないアプリケーション向け |
Resource Owner Password Credentialsの認証における指定パラメータ
- grant_type・・・password という文字列。Resource Owner Password Credentials であることを表す
- username・・・ログインするユーザ名
- password・・・ログインするパスワード
- scope・・・アクセスのスコープを指定する(省略可)
scopeはどんな権限にアクセスをさせるかを指定するもの。 スコープを使うことで外部サービスがトークンを得る際にアクセス内容を制限し、またユーザに「このサービスは以下の情報にアクセスできますよ」と表示することができる。
クライアントのリクエストは例えば以下のようになる。
POST /v1/oauth2/token HTTP/1.1
Host: api.example.com
Authorization: Basic Y2xpZW50X21kOmNsaWVudF9zZWNyZXQ
Content-Type: application/x-www-form-urlencoded
grant_type=password&username&takaaki&password&abcde&scope=api
正しくサーバに送られるとサーバは以下のようなJSONをレスポンスする。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_toke": "b77yz37w7kzy8v5fuga6zz93",
"token_type": "bearer",
"expires_in": 2620743,
"refresh_token": ""
}
bearerトークンの送信方法はRFC 6750によれば以下の3種類ある。
- リクエストヘッダに入れる方法
- リクエストボディに入れる方法
- URI にクエリパラメータとして入れる方法
expires_in
はアクセストークンが後何秒で有効期限切れになるかを表したもの。
有効期限が切れた場合、サーバは invalid_token というエラーを 401 で返すことになっている。
invalid_token が発生した場合にはリフレッシュトークンを使ってアクセストークンを再度要求することができる。 リフレッシュトークンは返さないことも可能(その場合は再ログインが必要となる)。
ユーザ名やパスワードによらず API を利用させたい場合はClient Credentialsを使うのが良い ClientID と ClientSecret さえ取得してアプリケーションに埋め込んでおけばpublicな情報にアクセスできる。
1.5. SSKDsとAPIのデザイン
Web APIは大きく2種類に分けられる。
- LSUDs 向け ・・・一般に公開し多くの人たちに使ってもらうためのAPI
- SSKDs 向け ・・・自社のスマホアプリなど特定の人だけが使うAPI
SSKDs 向けのAPIでは必ずしも汎用的な美しいAPIを提供する必要はない。 ユーザ体験を考えるとホーム画面に表示する情報を1つに詰め込んだAPIを1個提供する方がいい場合もある。
1.6. HATEOASとREST API
1.6.1. HATEOAS(Hypermedia as the Engine of Application State)
HATEOASはRESTの一部であり、リソースに対する情報や操作について前情報なしに扱うことができるアーキテクチャパターンである。
言い換えるとRestful原則に対する追加的な制約であり、HTMLアプリの画面遷移を抽象化した状態遷移を表現するRestful APを設計するための具体的な方法論ともいえる。
例えば以下のようなAPIを設計したとする。
/books/isbn
これはAmazonの本の情報を得られるAPIであるとした場合、アクセスしたときのレスポンスは以下のようなものが考えれる。
- タイトル
- 作者
- 在庫数
- 評価 などなど
Book に対する情報が含まれることを期待します。 HATEOASではさらにBook に対してなにが出来るのかがすべて表現されます。
- 購入
- 作者の詳細をみる
- 評価の詳細をみる
- 評価を追加する などなど
最大の特徴はリソースにアクセスすることができる= ソースに対する操作が出来る(できないことは表現されない)。
1.7. GraphQL
GraphQLはGraphとQL(クエリー言語)を合わせたREST APIの代替規格。
GraphはGraphQLで扱うデータが以下の図のようにnodeとedgeを使ってグラフのように表されることからGraphという名前が利用されている。
クライアントからサーバに対してCRUDを行う際に利用するREST APIと同様にGraphQLもクライアントからサーバに対してCRUDする際に利用することができる。
REST APIではデータを取得する際に複数のエンドポイントを利用したが、GraphQLでは1つのエンドポイントのみ持ちクエリーを設定(問い合わせなのか更新または削除なのか、どのデータが欲しいかを指定)することでサーバからデータを取得することができる。
クエリーの設定によって一度のHTTPリクエストで一括でユーザ情報、ブログ記事情報を取得することも可能な上、ユーザ情報の中からはemailのみ選択して取得するといったことも可能。
1.7.1. GraphQLが解決したREST APIの問題
GraphQLはREST APIの抱える以下の問題を解決できる。
- 必要なデータを取得する際に1つのエンドポイントから十分なデータが取得できない場合に複数のエンドポイントに対してリクエストを送信しなければならなかったこと
- Overfetchingと呼ばれる問題
Overfetchingとは: ユーザデータの中からemailのみ取得するといったことができず必ず一緒に必要でない情報(ブラウザ上に描写しないデータ)を取得してしまうこと