Current section

Files

Jump to
ex_jira lib jirex utils request.ex
Raw

lib/jirex/utils/request.ex

require Logger
defmodule ExJira.Request do
@moduledoc """
Provides the base request function and helper functions for GET and POST.
All request functions return either {:ok, data} or {:error, reason}
"""
@type request_response :: {:ok, any} | {:error, any}
@spec jira_account() :: String.t
defp jira_account(), do: Application.get_env(:ex_jira, :account)
@spec jira_username() :: String.t
defp jira_username(), do: Application.get_env(:ex_jira, :username)
@spec jira_password() :: String.t
defp jira_password(), do: Application.get_env(:ex_jira, :password)
@spec jira_timeout() :: String.t
defp jira_timeout(), do: Application.get_env(:ex_jira, :timeout) || 30_000
@spec jira_client() :: atom
defp jira_client(), do: Application.get_env(:ex_jira, :http_client) || HTTPotion
@doc """
Sends a GET request to the specified resource_path with the specified query_params.
Sends multiple requests if more resources are available.
Note: REST endpoints that return all entries every time as a top level list
and never page (e.g. Project) should use `get_one/2` instead.
## Examples
iex> Request.get_all("/some/items", "items", "a=b&c=d")
{:ok, [%{"id" => "1002"},%{"id" => "1003"}]}
iex> Request.get_all("/some/failure", "items", "a=b&c=d")
{:error, "aliens"}
"""
@spec get_all(String.t, String.t, String.t) :: request_response
def get_all(resource_path, resource, query_params) do
request("GET", resource_path, query_params, "")
|> get_more([], resource_path, resource, query_params)
end
@doc """
Sends a GET request to the specified resource_path with the specified query_params.
Expects a single return item.
iex> Request.get_one("/one/widget", "c=d&e=f")
{:ok, %{"id" => "1006"}}
"""
@spec get_one(String.t, String.t) :: request_response
def get_one(resource_path, query_params) do
request("GET", resource_path, query_params, "")
end
@spec get_more(request_response, [...], String.t, String.t, String.t) :: request_response
defp get_more({:error, reason}, _, _, _, _), do: {:error, reason}
defp get_more({:ok, %{"total" => total} = response}, prev_items, resource_path, resource, query_params) do
items = response[resource]
case length(prev_items) + length(items) do
x when x >= total ->
{:ok, prev_items ++ items}
_ ->
request("GET", resource_path, "startAt=#{length(prev_items) + length(items)}&#{query_params}&maxResults=300", "")
|> get_more(prev_items ++ items, resource_path, resource, query_params)
end
end
@doc """
Sends a POST request to the specified resource_path with the specified
query_params (as a string in the form "key1=val1&key2=val2") and the
specified payload.
"""
@spec post(String.t, String.t, String.t) :: request_response
def post(resource_path, query_params, payload) do
request("POST", resource_path, query_params, payload)
end
@doc """
Sends a request using the specified method to the specified resource_path
with the specified query_params (as a string in the form "key1=val1&key2=val2")
and the specified payload.
## Examples
iex> ExJira.Request.request("GET", "/some/item", "a=b&c=d", "")
{:ok, %{"id" => "1001"}}
iex> ExJira.Request.request("GET", "/httpotion/failure", "a=b&c=d", "")
{:error, "some error"}
"""
@spec request(String.t, String.t, String.t, String.t) :: request_response
def request(method, resource_path, query_params, payload) do
url = "https://#{jira_account()}/rest/api/latest#{resource_path}?#{query_params}"
auth = get_auth()
Logger.debug("ExJira.Request: Sending #{method} to #{url} using #{jira_client()}")
case httpotion_request(jira_client(), method, url, payload, [timeout: jira_timeout(), headers: ["Content-Type": "application/json", "Authorization": auth]]) do
%HTTPotion.ErrorResponse{message: message} ->
{:error, message}
%HTTPotion.Response{status_code: 404} ->
{:error, "404 - Not Found"}
%HTTPotion.Response{body: body, headers: %{hdrs: %{"content-type" => "application/json;charset=UTF-8"}}} ->
Poison.decode(body)
%HTTPotion.Response{headers: %{hdrs: %{"content-type" => content_type}}} ->
{:error, "Invalid content-type returned: #{content_type}"}
end
end
def get_auth() do
auth = "#{jira_username()}:#{jira_password()}" |> Base.encode64
"Basic #{auth}"
end
@spec httpotion_request(atom, String.t, String.t, String.t, list) :: %HTTPotion.ErrorResponse{} | %HTTPotion.Response{}
defp httpotion_request(client, "GET", url, _payload, opts), do: client.get(url, opts)
defp httpotion_request(client, "POST", url, payload, opts), do: client.post(url, [body: payload] ++ opts)
end