We’ll need a JSON library to convert the response into a data structure. Searching hex.pm, I found the poison library (no relation to HTTPoison), so let’s add its dependency to our mix.exs file.[23]
| defp deps do |
| [ |
| { :httpoison, "~> 1.0.0" }, |
| { :poison, "~> 3.1" }, |
| ] |
| end |
Run mix deps.get, and you’ll end up with poison installed.
To convert the body from a string, we call the Poison.Parser.parse! function when we return the message from the GitHub API:
| def handle_response({ _, %{status_code: status_code, body: body}}) do |
| { |
| status_code |> check_for_error(), |
| body |> Poison.Parser.parse!() |
| } |
| end |
| |
| defp check_for_error(200), do: :ok |
| defp check_for_error(_), do: :error |
We also have to deal with a possible error response from the fetch, so back in the CLI module we write a function that decodes the body and returns it on a success response; the function extracts the error from the body and displays it otherwise.
| def process({user, project, _count}) do |
| Issues.GithubIssues.fetch(user, project) |
» | |> decode_response() |
| end |
| |
| def decode_response({:ok, body}), do: body |
| |
| def decode_response({:error, error}) do |
| IO.puts "Error fetching from Github: #{error["message"]}" |
| System.halt(2) |
| end |
The JSON that GitHub returns for a successful response is a list of maps, where each map in the list contains a GitHub issue.
Before we move on, there’s one little tweak I’d like to make. The issues_url function hard-codes the GitHub URL. Let’s make this configurable.
Remember that when we created the project using mix new, it added a config/ directory containing config.exs. That file stores application-level configuration.
It should start with the line
| use Mix.Config |
We then write configuration information for each of the applications in our project. Here we’re configuring the Issues application, so we write this code:
| use Mix.Config |
| config :issues, github_url: "https://api.github.com" |
Each config line adds one or more key/value pairs to the given application’s environment. If you have multiple lines for the same application, they accumulate, with duplicate keys in later lines overriding values from earlier ones.
In our code, we use Application.get_env to return a value from the environment.
| # use a module attribute to fetch the value at compile time |
| @github_url Application.get_env(:issues, :github_url) |
| |
| def issues_url(user, project) do |
| "#{@github_url}/repos/#{user}/#{project}/issues" |
| end |
Because the application environment is commonly used in Erlang code, you’ll find yourself using the configuration facility to configure code you import, as well as code you write.
Sometimes you may want to vary the configuration, perhaps depending on your application’s environment. One way is to use the import_config function, which reads configuration from a file. If your config.exs contains
| use Mix.Config |
| |
| import_config "#{Mix.env}.exs" |
then Elixir will read dev.exs, test.exs, or prod.exs, depending on your environment.
You can override the default config file name (config/config.exs) using the --config option to elixir.