HTTPoisonはHTTPクライアントのことです.なぜHTTPoisonを使うかというと,バックエンドはErlangのHackneyライブラリが使われているからです.Hackneyはバイナリを使うので,それが気に入っています.今回GithubのAPIを通して,HTTPoisonライブラリの基本的な使い方をまとめたいと思います.
Setup
$ mix new githubapi --module Github
mix.exsへ以下の記述を追加します.
def application do
# ここに`:httpoison`を書いておくとモジュールに`HTTPoison.startを書かなくても済む
[applications: [:logger, :httpoison]] end
def deps do
[{:httpoison, "~> 0.7.2"},
{:poison, "~> 1.5"}
]
end
$ mix deps.get
lib/githubapi.ex
ファイルは以下のようになっています.
defmodule Github do
def zen do # これから実装する関数
...
end
def list_repos do
...
end
...
...
end
GET 禅
毎回違う禅
を取得してみます.
$ curl https://api.github.com/zen
Anything added dilutes everything else.
HTTPoisonでのやり方
def zen do
url = "https://api.github.com/zen"
response = HTTPoison.get!(url)
Logger.info "レスポンス: #{inspect response}"
end
実行結果
$ iex -S mix
iex(1)> Github.zen
18:37:09.866 [info] レスポンス: %HTTPoison.Response{body: "Non-blocking is better than blocking.", headers: [{"Server", "GitHub.com"}, {"Date", "Sat, 12 Sep 2015 09:37:08 GMT"}, {"Content-Type", "text/plain;charset=utf-8"}, {"Content-Length", "37"}, {"Status", "200 OK"}, {"X-RateLimit-Limit", "60"}, {"X-RateLimit-Remaining", "57"}, {"X-RateLimit-Reset", "1442051552"}, {"X-XSS-Protection", "1; mode=block"}, {"X-Frame-Options", "deny"}, {"Content-Security-Policy", "default-src 'none'"}, {"Access-Control-Allow-Credentials", "true"}, {"Access-Control-Expose-Headers", "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval"}, {"Access-Control-Allow-Origin", "*"}, {"X-GitHub-Request-Id", "6A89D658:C023:20C345:55F3F243"}, {"Strict-Transport-Security", "max-age=31536000; includeSubdomains; preload"}, {"X-Content-Type-Options", "nosniff"}, {"Vary", "Accept-Encoding"}, {"X-Served-By", "b0ef53392caa42315c6206737946d931"}], status_code: 200}
:ok
レスポンスを見てみると%HTTPoison.Response{body: ..., headers: ..., status_code: ...}
のような形のstructです.その中のbody
フィールドを抽出するのは簡単(response.body)です.
def zen do
url = "https://api.github.com/zen"
response = HTTPoison.get!(url)
# Logger.info "レスポンス: #{inspect response}"
# bodyを抽出
body = response.body
Logger.info "body: #{inspect body}"
end
結果
iex(1)> Github.zen
18:52:19.126 [info] body: "Encourage flow."
get!
関数の最後に!
が付いているのは理由についてソースを見てみましょう.要は失敗すると例外を起こすようにすることです.
Issues a GET request to the given url, raising an exception in case of failure.
すでに気づいたと思いますが,レスポンスの中のheaders
はtuple
のlist
になっています.Enumを使って,headers
を出力してみます.
def zen do
url = "https://api.github.com/zen"
response = HTTPoison.get!(url)
# Logger.info "レスポンス: #{inspect response}"
# bodyを抽出
# body = response.body
# Logger.info "body: #{inspect body}"
# headerを出力
headers = response.headers
Enum.map(headers, fn {header, value} -> IO.puts "#{header}: #{value}\n" end)
end
結果
iex(1)> Github.zen
Server: GitHub.com
Date: Sat, 12 Sep 2015 10:16:20 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 26
Status: 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
......
......
[:ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok,
:ok, :ok, :ok]
Githubのrepoをリストアップ
認証されたユーザーとしてレポジトリをリストアップしてみます.そのためにtoken
が必要で,ここで生成することができます.
$ curl -i -H 'Authorization: token ****************************************' https://api.github.com/user/repos
HTTPoisonでのやり方
def list_repos do
url = "https://api.github.com/user/repos"
token = "***************************************"
headers = [{"Authorization", "token #{token}"}]
response = HTTPoison.get!(url, headers)
Logger.info "response: #{inspect response.body}"
結果
大量なデータが出力されるので,省いておきます.
iex(1)> Github.list_repos
:ok
19:50:59.235 [info] response: "[{\"id\":9593030,\"name\":\"Addition\",
.....
.....
.....
]
これでget!
関数にheaerの追加のやり方も分かりました.どんなフォーマットの引数を渡せばいいかを知るためにソースコードを見るとわかります.
レポジトリのIssueを作成 (POST)
このAPIの仕様はここからアクセスできます.
$ curl -i -H 'Authorization: token ***************************************' \
> -d '{
> "title": "New logo",
> "body": "We should have one",
> "labels": ["design", "feature"]
> }' https://api.github.com/repos/ColdFreak/ppool/issues
ここでjson形式のPOSTデータを送ります."labels"の部分2つの要素が入っているリストになっています.
HTTPoisonでのやり方
def create_issue do
url = "https://api.github.com/repos/ColdFreak/ppool/issues"
token = "***************************************"
response = HTTPoison.post!(url, "{\"title\": \"Add variable\", \"body\": \"Add max overflow\", \"labels\": [\"design\", \"feature\"\]}", %{"Authorization" => "token #{token}"})
Logger.info "response: #{inspect response}"
end
post!
関数の使い方は同じくソースコードの中で調べるとわかります.
def post!(url, body, headers \\ [], options \\ []), do: request!(:post, url, body, headers, options)
二番目の引数に直接json形式のデータを作って渡しています.labels
の部分は配列になっています.三番目の引数はheader
で,上のようなMapの形で渡しても大丈夫です.
作成されていることは確認できました.
もう一つのやり方はPoison
というJSONライブラリを使う方法です.
def create_issue_2 do
url = "https://api.github.com/repos/ColdFreak/ppool/issues"
token = "***************************************"
headers = [{"Authorization", "token #{token}"}]
json_data = %{title: "test issue", body: "test body", labels: ["design", "feature"]} |> Poison.encode!
response = HTTPoison.post!(url, json_data, headers)
Logger.info "response: #{inspect response}"