326 words, 2 min read

I came across this example of how nice and concise Elixir can be. It's a simple Github API client that does quite a bit in a small space. I like it.

Elixir can pack a lot into a little. I do have doubts if I'm over compacting it a bit but but frankly I like this. Here's a simple snippet of a Github API Client doing quite a bit of lifting in a small space.

defmodule Github.API do
@moduledoc """
Provides common functions to extract data from the Github API.
"""
@base_api_url "https://api.github.com/"
alias Github.UserRepository
alias Github.UserProfile
alias Github.UserEvents
alias Github.UserGists
@doc "Get the user profile"
def get_user_profile(username),
do: get("users/#{username}") |> handle_response(&UserProfile.new/1)
@doc "get the user profile, raise an exception if not ok"
def get_user_profile!(username), do: get_user_profile(username) |> unwrap_or_raise!()
@doc "get the users' repositories"
def repositories(username),
do: get("users/#{username}/repos") |> handle_response(&UserRepository.new/1)
@doc "get the users' repositories or raise an exception"
def repositories!(username), do: repositories(username) |> unwrap_or_raise!()
@doc "get the events for a user"
def events(username),
do: get("users/#{username}/events") |> handle_response(&UserEvents.new/1)
@doc "get the events for a user, raise an exception on error"
def events!(username), do: events(username) |> unwrap_or_raise!()
@doc "get the gists for a user"
def gists(username),
do: get("users/#{username}/gists") |> handle_response(&UserGists.new/1)
@doc "get the gists for a user, raise an exception on error"
def gists!(username), do: gists(username) |> unwrap_or_raise!()
# Handle unwrap functions
defp unwrap_or_raise!({:ok, res}), do: res
defp unwrap_or_raise!({:error, reason}),
do: raise("Github API request failed: #{inspect(reason)}")
# Start basic client functions here, these focus on the actual request and body
defp get_service_token(), do: Application.fetch_env!(:service, :github_api_token)
defp headers(), do: [{"Authorization", "Bearer #{get_service_token()}"}]
defp request_url(path), do: "#{@base_api_url}#{path}"
defp get(path), do: HTTPoison.get(request_url(path), headers())
defp handle_response({:ok, %HTTPoison.Response{status_code: 200, body: body}}, _transform) do
case Poison.decode(body) do
{:ok, parsed_body} when is_list(parsed_body) ->
{:ok, Enum.map(parsed_body, _transform)}
{:ok, parsed_body} ->
{:ok, transform(parsed_body)}
{:error, reason} ->
{:error, {:decode_failed, reason}}
end
end
defp handle_response({:ok, %HTTPoison.Response{status_code: code}}, _transform), do: {:error, {:unhandled_status_code, code}}
end

Thanks to ChatGPT for converting the code in the source image to actual code.

source