Elixir
httpoison

ElixirのHTTPoisonライブラリの使い方

More than 1 year has passed since last update.

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.

すでに気づいたと思いますが,レスポンスの中のheaderstuplelistになっています.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の形で渡しても大丈夫です.

作成されていることは確認できました.

スクリーンショット 2015-09-12 22.21.43.png

もう一つのやり方は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}"

Mapでデータを準備して,Poison.encode!渡して,JSONを生成してくれます.
スクリーンショット 2015-09-12 22.36.52.png