【エンジニア初学者向け】これだけは抑えておきたいAPI接続に必要なHTTPプロトコルの基礎知識
どうも、スウェーデンでITエンジニアをしているあめぞう(@amezousan)です。
今回はAPI接続に必要なHTTPプロトコルの基礎知識について書きます。
インフラを経験していないエンジニアほど「HTTPプロトコル基礎」を学ばずに何となくでAPI接続を済ませてる人、苦手意識を持っている人が結構居ることに気がつきました。
基礎を知れば「API接続はとても簡単である」と言うことをお伝えできればと思い本記事を書いています。
主な読者ターゲットは以下を想定しています。
- エンジニア経験 1~2年目の人達
- インフラ知識を我流で学んできたエンジニアの人達
では早速解説していきます。
はじめに
皆さんはブラウザに「google.com」と入力して、どのようにしてGoogleのサイトが表示されるかをご存知でしょうか。
こちらを説明する上で書かせないのがネットワーク用語における「OSI参照モデル」です。ネットワーク接続における仕組みを7つの階層に分け、統一化したモデルです。
現在のネットワークは上記モデルに従って設計されており、非常に分かりやすい構造になっています。こちらの概念が分かると先ほどのGoogleに繋がるまでの過程が理解できます。
「もっと詳しく知りたい!」と言う方には、知る人ぞ知る「3分間ネットワーキング」[1]で各層ごとの役割を学ぶことが可能です。
(サイトより引用)
ネットワークの知識は難しい?
よくわからない言葉の羅列で意味がわからない?誰にでもよくわかるネットワーク講座をここに開講!
今回はその中でも「HTTPプロトコル[2]」に焦点を当てて解説します。
ブラウザでウェブページが表示される仕組み
皆さんご存知の「http://, https://」は「HTTPプロトコル」におけるスキーマ(何の処理方式でアクセスするか)を指しています。
例えば「https://google.com/」とアクセスした場合、以下のような通信がブラウザの裏で発生しています。
HTTPリクエスト
GET / HTTP/1.1
Host: google.com
...(ブラウザの情報など)...
(⏫必ず改行が必要⏫)
それぞれを分解すると以下の通りになります。
GET | / | HTTP/1.1 |
---|---|---|
HTTPメソッド | URLのパス | HTTPプロトコルのバージョン |
- Host はアクセス先のドメイン名を書きます。
- HTTPリクエストで最低限必要なのは1, 2行目(GET, Host)と改行のみです。
HTTPレスポンス
HTTP/1.1 301 Moved Permanently
Location: https://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Thu, 15 Oct 2020 09:29:35 GMT
Expires: Sat, 14 Nov 2020 09:29:35 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 220
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Alt-Svc: h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>
そして気がついた人がいるかもしれませんが、HTTPレスポンスでは改行をはさんで異なる情報が表示されています。改行上を「レスポンスヘッダ」、改行下を「レスポンスボディ」 と言います。
このヘッダ、ボディは「HTTPリクエスト」においても同様に存在します。まとめると次の通りになります。
用語 | ヘッダ | ボディ |
---|---|---|
HTTPリクエスト | サイトアクセスの方式・付加情報(データ形式、ブラウザ情報、認証情報など) | サイトアクセスで用いるデータ |
HTTPレスポンス | アクセス結果のステータス日時、サーバからの付加情報 | ブラウザで表示されるコンテンツデータ |
もっとザックリ言うと次の通りです。
- HTTPリクエスト: サイトアクセスに必要なデータ
- HTTPレスポンス: 対象のウェブサイトから返ってくる情報
ブラウザでウェブページが表示される仕組みは以下の通りになります。
- ブラウザがユーザの入力データに応じてHTTPリクエストを投げる
- 対象のウェブサイトはリクエストを処理、HTTPレスポンスを返す
- ブラウザはレスポンスボディのHTML, JavaScript, CSS等の描写処理を行う
ではAPI接続で良く出てくるHTTPプロトコルについて見ていきましょう。
API接続で良く出てくるHTTPプロトコル
API接続、と言っても実際には「HTTPプロトコル」のルールに基づいて適切な「HTTPリクエスト」を投げるだけです。
そしてAPIで行われる動作を4つにまとめた「CRUD(クラッド)」と言う用語があります。
CRUD(クラッド)と言う考え方
- C reate: 新規作成
- R ead: 読み込み
- U pdate: 更新
- D elete: 削除
上記はウェブアプリケーションにおける動作です。
更に各動作において慣習的に使われる「HTTPメソッド」があります。
HTTPメソッド | 動作 |
---|---|
GET | 読み込み |
POST | 新規作成, 更新 |
PUT | 新規作成, 更新 |
PATCH | 新規作成, 更新 |
DELETE | 削除 |
「新規作成, 更新」においては3つのHTTPメソッドがありますが基本的な考え方はこちらの記事 - PUT か POST か PATCH か?が参考になります。
基本的な考え方
---
PUT: リソースの作成、リソースの置換
POST: リソースの作成
PATCH: リソースの部分置換
そして「POST/PUT/PATCH」は「リクエストボディ」を受け付けますが「GET/DELETE」はHTTPプロトコルの仕様上、原則としてリクエストボディを受け取りません。
📘ちょっと小話📘
過去に「POST/PUT/PATCH/DELETE」の動作を全て「POST」メソッドで実装しているウェブアプリを見たことがあります😂
CRUDで使われるHTTPメソッドは「あくまでも」理想的な使い方であって開発者に強制している訳ではありません。
その中で「PUT/POST/PATCH」を細かく使い分けるか、は開発者の考え方によって異なります。
curl
って何者?
API接続で良く出てくるAPI接続でcurl
と言うコマンドが良く出てきます。これはHTTPリクエストを全て手書きすることなくリクエストを生成できる優れたツールです。
少し難しいように感じますが先ほど紹介したHTTPリクエストをオプション付きで生成するだけなので特に怖がる必要はありません。
ここではAPI接続で抑えておくべきcurlオプションを紹介します。
$ curl -h
-h
オプションは色んなコマンドでヘルプを表示する際に使われます。コマンドによっては-h
ではなく「help, --help
」などの変わり種も存在します。
-
-d, --data <data>
: HTTPリクエストボディで使うデータを入力します。 -
-H, --header <header/@file>
: HTTPリクエストヘッダで使うデータを入力します。 -
-k, --insecure
: HTTPSでのアクセスにおいて、対象サイトでSSL証明書の警告がある場合接続できません。接続先が安全であることが分かっている場合は「-k
」オプションを使うと証明書の警告を回避できます。 -
-X, --request <command>
: HTTPメソッド(GET/POST/PUT/etc)を入力します。 -
-u, --user <user:password>
: Basic認証[3]を自動で生成してくれるオプションです。
ではHTTPメソッド別にcurlとリクエストを対比してみましょう。各HTTPリクエストは見やすいように加工しています。
-X
オプションは、実はcurl側で自動認識する機能がついているので省略可能な場合があるのですが明示的に書きます。
今回リクエストを投げる先は「Postman[4]」のドキュメントに記載があるテストサイトにします。-> https://docs.postman-echo.com/
GETメソッド (curl, HTTPリクエスト例)
curl -X GET https://postman-echo.com/get?foo1=bar1&foo2=bar2
# HTTPリクエスト
GET /get?foo1=bar1 HTTP/1.1
Host: postman-echo.com
User-Agent: curl/7.64.1
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 08:24:32 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 265
{"args":{"foo1":"bar1"},"headers":{"x-forwarded-proto":...
URLの後にハテナマーク(?)がありますが、こちらもアクセス先の入力データとして扱われます。リクエストボディではなく「クエリ(Query)」と言う名称がついています。
「key(キー)=value(値)」の形式で入力され、アンド(&)で複数入力が可能です。
POSTメソッド (curl, HTTPリクエスト例)
「POST/PUT/PATCH」メソッドで使用するデータ形式として「form」や「json」があります。
- FORM形式(例: Content-Type: application/x-www-form-urlencoded):
curl -X POST https://postman-echo.com/post -d "key1=value1" -d "key2=value2"
# HTTPリクエスト
POST /post HTTP/1.1
Host: postman-echo.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
key1=value1&key2=value2
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 08:38:32 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 419
{"args":{},"data":"","files":{},"form":{"key1":"value1","key2":"value2"},...
「Content-Length」はリクエストヘッダで投げるデータの長さを指定します。例えば「4」とするとリクエストボディの先頭文字「key1」だけが送信されます。ブラウザやcurlを使うとこれらの計算は自動で行われます。
- JSON形式 (Content-Type: application/json):
curl -X POST https://postman-echo.com/post -d '{"key1":"value1", "key2": "value2"}' -H "Content-Type: application/json"
# HTTPリクエスト
POST /post HTTP/1.1
Host: postman-echo.com
Content-Type: application/json
Content-Length: 35
{"key1":"value1", "key2": "value2"}
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 08:50:06 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 402
{"args":{},"data":{"key1":"value1","key2":"value2"},"files":{},"form":{},...
PUT/PATCHメソッド (curl, HTTPリクエスト例)
curl -X PUT https://postman-echo.com/put -d 'key1=value1&key2=value2'
# HTTPリクエスト
PUT /put HTTP/1.1
Host: postman-echo.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: close
key1=value1&key2=value2
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 08:56:29 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 418
{"args":{},"data":"","files":{},"form":{"key1":"value1","key2":"value2"},...
curl -X PATCH https://postman-echo.com/patch -d 'key1=value1&key2=value2'
# HTTPリクエスト
PATCH /patch HTTP/1.1
Host: postman-echo.com
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: close
key1=value1&key2=value2
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 08:59:13 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 420
{"args":{},"data":"","files":{},"form":{"key1":"value1","key2":"value2"},...
例を見るとPOST/PUT/PATCHも全て似た形式を取ることが分かります。更に最近良く使われるリクエストボディの形式は「json/form」がほとんどなのでそれさえ気をつけていれば特に困ることはありません。
では次に認証周り(BASIC, OAuth/etc)についてどんな通信が発生しているのかを見ていきましょう。
HTTPリクエストで見るBasic認証とOAuth認証の違い
Basic認証
curl -X GET https://postman-echo.com/basic-auth -u 'postman:password'
# HTTPリクエスト
GET /basic-auth HTTP/1.1
Host: postman-echo.com
Authorization: Basic cG9zdG1hbjpwYXNzd29yZA==
# HTTPレスポンス
HTTP/1.1 200 OK
Date: Sun, 18 Oct 2020 09:02:44 GMT
Content-Length: 22
{"authenticated":true}
-u
オプションを使わずに-H "Authorization: Basic cG9zdG1hbjpwYXNzd29yZA=="
としても同じリクエストが投げれます。uオプションはあくまでも入力値を自動的に暗号化してくれるものです。
Basic認証は「postman:password」をBase64エンコードしたものを利用します。非常に簡単に暗号化・複合化(元に戻す)が可能なのでセキュリティ的には非常に弱いです。👉base64エンコード/デコードツール
OAuth認証
ここではTwitterのOAuth認証を例にして説明します。
# HTTPリクエスト
POST https://api.twitter.com/1.1/statuses/update.json?status=Hello%20world
Host: api.twitter.com
Authorization: OAuth oauth_consumer_key="CONSUMER_API_KEY",...
# HTTPリクエスト
GET https://api.twitter.com/2/tweets?ids=1278747501642657792
Host: api.twitter.com
Authorization: Bearer ...
OAuth 1.0と2.0認証においては「Authorization」ヘッダの値が上記例のように異なります。
実際の認証フローに関しては下記サイトが参考になります。
最後に
いかがでしたでしょうか。API接続において必要となる基礎知識を埋め込んだつもりですが思いの外、かなりの予備知識を必要とすることが理解できました。
HTTPプロトコルは非常にシンプルな形式です。まずはcurl
で動くサンプルを試してみて、HTTPプロトコルに置き換えた際にどのような形式になるのかを考えることができるとAPI接続で困ることはまず無いのかな、と思います。
初学者の方にとって難しい部分ではあるものの、基礎を抑えると後の応用が非常に楽になってくるのでここは力を入れて勉強したい分野でもあります。
本記事が皆さんの学習に役立つことを願いつつ、これにてお終いです。
ではまた、Vi ses!
Discussion
すごくわかりやすくて、ためになりました。ありがとうございます!
お役に立てて何よりです!
Oauth1.0認証 というところの # HTTPリクエスト のあたりで "OAuth 1.0のAPIアクセス方法" で OAuth 2.0 の アクセストークンを要求する内容が例示されているように見えるのですが、ここでは何を説明しようとしているのでしょうか?
該当箇所の説明が少し不明瞭だったので追記しました。お知らせありがとうございます!
OAuth 1.0のAPIアクセスを説明しようとしていることは推測できるのですが、それであれば multipart/form-dataとしてcode, grant_type, client_id ... などの OAuth 2.0用のパラメータを送る必要はないのではないでしょうか?1.0と2.0を混在させるようなリクエストは実際には使われていませんし、読者に混乱を招きかねません。
例えばですが、OAuth 1.0では
のようなリクエストとなり、OAuth 2.0(のAPIアクセス)では
のようになってますよ、ぐらいで十分かと思います。
色々と助かります!TwitterのOAuth認証サンプルが非常にスッキリしていたのでそちらを参考にして触りの部分だけ変更しています。
あー、すみません。Postmanの記事にある例をそのまま使われてたんですね。こっちに問い合わせしておきます。
非常にわかりやすかったです。
ありがとうございます!