Your Turn

Back to the Transformation

So, back to our problem. We have to write the function GithubIssues.fetch, which transforms a user name and project into a data structure containing that project’s issues. The HTTPoison page on GitHub gives us a clue,[22] and we write a new module, Issues.GithubIssues:

project/1a/issues/lib/issues/github_issues.ex
 defmodule​ Issues.GithubIssues ​do
  @user_agent [ {​"​​User-agent"​, ​"​​Elixir dave@pragprog.com"​} ]
 
 def​ fetch(user, project) ​do
  issues_url(user, project)
  |> HTTPoison.get(@user_agent)
  |> handle_response
 end
 
 def​ issues_url(user, project) ​do
 "​​https://api.github.com/repos/​​#{​user​}​​/​​#{​project​}​​/issues"
 end
 
 def​ handle_response({ ​:ok​, %{​status_code:​ 200, ​body:​ body}}) ​do
  { ​:ok​, body }
 end
 
 def​ handle_response({ _, %{​status_code:​ _, ​body:​ body}}) ​do
  { ​:error​, body }
 end
 end

We simply call get on the GitHub URL. (We also have to pass in a user-agent header to keep the GitHub API happy.) What comes back is a structure. If we have a successful response, we return a tuple whose first element is :ok, along with the body. Otherwise we return an :error tuple, also with the body.

There’s one more thing. The examples on the HTTPoison GitHub page call HTTPoison.start. That’s because HTTPoison actually runs as a separate application, outside your main process. A lot of developers will copy this code, calling start inline like this.

In older versions of Elixir, you could add HTTPoison to the list of applications to start in mix.exs:

 def​ application ​do
  [ ​applications:​ [ ​:logger​, ​:httpoison​ ] ]
 end

This is no longer necessary. The fact that you have listed HTTPoison as a dependency means that mix will automatically start it as an application.

We can play with this in IEx. Use the -S mix option to run mix before dropping into interaction mode. Because this is the first time we’ve tried to run our code since installing the dependencies, you’ll see them get compiled:

 $ iex -S mix
 Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-thr
 eads:10] [hipe] [kernel-poll:false]
 
 ===> Compiling mimerl
 ===> Compiling metrics
  : :
 Generated issues app
 
 iex(1)>

Let’s try it out. (The output is massaged to fit the page.)

 iex>​ Issues.GithubIssues.fetch(​"​​elixir-lang"​, ​"​​elixir"​)
 {:ok,
 [
  {"url":"https://api.github.com/repos/elixir-lang/elixir/issues/7121",
  "repository_url":"https://api.github.com/repos/elixir-lang/elixir",
  "labels_url":
  "https://api.github.com/repos/elixir-lang/elixir/issues/7121/labels{/name}",
  "events_url":"https://api.github.com/repos/elixir-lang/elixir/issues/7121/events",
  "html_url":"https://github.com/elixir-lang/elixir/issues/7121",
  "id":282654795,
  "number":7121,
  "title":"IEx.Helpers.h duplicate output for default arguments",
  "user":{
  "login":"wojtekmach",
  "id":76071,
  "avatar_url":"https://avatars0.githubusercontent.com/u/76071?v=4",
  "gravatar_id":"",
  "url":"https://api.github.com/users/wojtekmach",
  "html_url":"https://github.com/wojtekmach",
  "followers_url":"https://api.github.com/users/wojtekmach/followers",
  . . . . . . .

This tuple is the body of the GitHub response. The first element is set to :ok. The second element is a string containing the data encoded in JSON format.