ElixirでHTTPリクエスト

[fukuoka.ex](https://fukuokaex.fun/)のkoyoです
最近Goばっかり書いているのでそろそろElixirするかということで書いてみます！

## お題
Github API を使って特定のリポジトリのcloseされたPR一覧を出してみる

## プロジェクトの作成
`mix new sample_ex`

## 必要なライブラリの追加
今回はHTTPリクエストに[HTTPoison](https://hexdocs.pm/httpoison/readme.html), レスポンスボディのパースに[Poison](https://github.com/devinus/poison)を使います

```elixir:mix.exs
defp deps do
    [
      {:httpoison, "~> 1.5"},
      {:poison, "~> 4.0"}
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    ]
  end
```

## 実装
対象リポジトリは昔作った[グラフ付きQiita検索アプリ](https://qiita-search.netlify.com/#/)
https://github.com/koyo-miyamura/vue_api_spa

```elixir:sample_ex.ex
defmodule SampleEx do
  @moduledoc """
  Documentation for SampleEx.
  """

  @spec main :: :ok
  def main() do
    pr_list() |> Enum.each(fn x -> IO.puts(x) end)
  end

  @spec pr_list :: charlist()
  def pr_list() do
    build_url("https://api.github.com/repos/koyo-miyamura/vue_api_spa/pulls", %{
      "state" => "closed"
    })
    |> HTTPoison.get!()
    |> Map.get(:body)
    |> Poison.decode!()
    |> Enum.map(fn x -> format(x) end)
  end

  @doc """
  build url.

  ## Examples

      iex> SampleEx.build_url("http://example.com", %{"foo" => "bar"})
      "http://example.com?foo=bar"

  """
  @spec build_url(String.t(), map()) :: String.t()
  def build_url(path, query) do
    URI.parse(path)
    |> Map.put(:query, URI.encode_query(query))
    |> URI.to_string()
  end

  @doc """
  format map

  ## Examples

      iex> SampleEx.format(%{"title" => "title", "created_at" => "2018-10-06T23:46:53Z"})
      "title 2018-10-06"
  """
  @spec format(map()) :: String.t()
  def format(map) do
    map_title = Map.get(map, "title")

    map_date =
      Map.get(map, "created_at")
      |> NaiveDateTime.from_iso8601!()
      |> NaiveDateTime.to_date()
      |> Date.to_string()

    map_title <> " " <> map_date
  end
end
```

Elixirで時刻扱うのはちょっとクセありますがこんな感じで
https://hexdocs.pm/elixir/NaiveDateTime.html#content

またURI文字列を作成する部分は`URI`モジュールを使えば良いですが、クエリパラメータを結合する関数は用意されていなかったので以下を参考に自前で作ってみました
https://stackoverflow.com/questions/49508509/idiom-to-construct-a-uri-with-a-query-string-in-elixir

## 実行結果
```bash

ｷﾀ━(ﾟ∀ﾟ)━! $ iex -S mix
Erlang/OTP 21 [erts-10.3.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> SampleEx.main
ユーザランキング 2018-10-06
vuexの導入 2018-10-06
チャート機能の実装 2018-10-06
Tag search 2018-10-05
Fix design 2018-10-04
Use vue cli 2018-09-30
vue-routerの導入 2018-09-29
Use component 2018-09-26
formから検索ワード変更する機能の追加 2018-09-25
見た目の調整 2018-09-24
```

できたぜ！！

## テストについて
できる部分はdoctestしましたが、HTTPリクエストを行う`pr_list`のテストはどうするのか分からず断念
Goだと`net/http`使ってモックするやり方が考えられますが、[Elixirはモックを推奨していない様子](https://elixirschool.com/ja/lessons/basics/testing/#%E3%83%A2%E3%83%83%E3%82%AF)

探してみると自前でサーバ立てるやり方が書いてました
んーちょっと大変？もっといいやり方募集中です
https://medium.com/flatiron-labs/rolling-your-own-mock-server-for-testing-in-elixir-2cdb5ccdd1a0

## ちなみにHTMLをパースしたい場合
[Floki](https://hexdocs.pm/floki/Floki.html)というライブラリがメジャーみたいです
`mix.exs`に`{:floki, "~> 0.21.0"}`
すると使えます

## 感想
最近Goばっかり書いてたんですが「GoでやるアレElixirでどうするんだろう？」という題材で学習してみると学びが深まりました
iex使って動かしながら作れるので楽しい
皆さんも普段使っている言語でやっていることをElixirで実現してみると面白いですよ！