LoginSignup
15
15

More than 5 years have passed since last update.

Phoenix で外部 API にリクエストする API を作る

Posted at

Phoenix で外部 API にリクエストする API を作ってみます。OpenWeatherMap API に問い合わせて、指定された緯度経度の天気を JSON で返却するという 無駄な挙動をさせてみましょう。

Phoenix で JSON API 作る方法はコチラを参照してください。

依存関係に HTTPoison を追加する

Elixir 版のサードパーティライブラリアーカイブ(PyPI や npm といった類のもの)には Hex があります。
ここに公開されているライブラリは Mix を使うことで簡単にプロジェクトに追加でき、またこれらの依存関係は mix.exs というファイルで管理できます。

今回は HTTP Client として HTTPoison を利用しますので、以下のように追記します。

mix.exs
  ...

  # Specifies your project dependencies
  #
  # Type `mix help deps` for examples and options
  defp deps do
    [{:phoenix, "~> 0.17"},
     {:phoenix_ecto, "~> 1.1"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.1"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:cowboy, "~> 1.0"},
     # HTTPoison を追記
     {:httpoison, "~> 0.7.2"}]
  end
end

その後、以下のコマンドを実行すると、ファイルがダウンロードされます。

$ mix deps.get

サーバを起動している場合は、忘れずに再起動しておきましょう。

ルートを追加する

/api/weahter/:lat/:lon で天気を問い合わせられるようにします。

router.ex
  scope "/api", SampleApp do
    pipe_through :api

    get "/weather/:lat/:lon", PageController, :weather
  end

OpenWeatherMap API に問い合わせる

コントローラに HTTP リクエストの処理を書きます。

page_controller.ex
  ...

  def weather(conn, %{"lat" => lat, "lon" => lon}) do
    HTTPoison.start
    result = HTTPoison.get! "http://api.openweathermap.org/data/2.5/weather?units=metric&lat=#{lat}&lon=#{lon}"

    case result do
      %{status_code: 200, body: body} -> json conn, Map.get(Poison.decode!(body), "main")
      %{status_code: code} -> json conn, %{error: code}
    end
  end
end

HTTPoison.start の後に HTTPoison.get! とすることで GET リクエストが発行されます。
OpenWeatherMap API のエンドポイントに対して入力された緯度経度を与えます。Elixir では文字列の中に #{...} と記述することで、変数を結合させられます。

リクエスト結果は変数 result に束縛させ、case に渡します。

case 構文のなかではパターンマッチが行われます。
1つ目の句は、status_code が 200 のときにマッチします。マッチングの際に body プロパティの中身を変数 body に束縛しておき、中の処理でそれのデコードと返却をします。
Elixir の句は上から順に評価されるため、status_code が 200 以外のリクエストは自然と2つ目の句にマッチします。この場合は status_code を束縛しておき、それを返却します。

ちなみに、Elixir の関数名には ! が付いているものと付いていないものがありますが、これにはエラーを発生させるかどうかの違いがあります。
例えば上記の HTTPosion.get! には HTTPoison.get もあり、返却はそれぞれ以下のようになります。

iex> HTTPoison.get! "..."
%HTTPoison.Response{ ... }
iex> HTTPoison.get "..."
{:ok, %HTTPoison.Response{ ... }}

get!/1 の場合は関数実行時にエラーが発生した場合はそのままスローされます。
一方、get/1 の場合はエラーは一切スローされず {:error, ...} という返却がされます。
エラーハンドリング次第で使い分ける、という感じですね。

リクエストしてみる

サーバを起動してリクエストしてみましょう。
六本木ヒルズの緯度経度を投げてみます。

$ curl -s "http://localhost:4000/api/weather/35.6585373/139.7151887" | jq .
{
  "humidity": 100,
  "pressure": 1015,
  "temp": 20.21,
  "temp_max": 23.33,
  "temp_min": 15.56
}

ちゃんとそれっぽい数値が取れました。

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15