Packages

A complete, production-grade Elixir client for the Monzo API: OAuth2, Accounts, Balance, Pots, Transactions, Feed Items, Attachments, Transaction Receipts, and Webhooks. Zero required dependencies.

Current section

Files

Jump to
monzo_client lib monzo http httpc_adapter.ex
Raw

lib/monzo/http/httpc_adapter.ex

defmodule Monzo.HTTP.HttpcAdapter do
@moduledoc """
Default Monzo.HTTP.Adapter implementation, built on Erlang's `:httpc`.
Requires the `:inets` and `:ssl` applications (both part of a standard
Erlang/OTP install) to be started, which Monzo.Application ensures.
"""
@behaviour Monzo.HTTP.Adapter
@impl true
def request(
%{method: method, url: url, headers: headers, body: body, timeout_ms: timeout_ms},
_opts
) do
erl_url = String.to_charlist(url)
erl_headers =
Enum.map(headers, fn {k, v} -> {String.to_charlist(k), String.to_charlist(v)} end)
http_opts = [timeout: timeout_ms, connect_timeout: timeout_ms]
opts = [body_format: :binary]
result =
case {method, body} do
{:get, _} ->
:httpc.request(:get, {erl_url, erl_headers}, http_opts, opts)
{:delete, nil} ->
:httpc.request(:delete, {erl_url, erl_headers}, http_opts, opts)
{method, body} ->
content_type = content_type_of(headers)
body = body || ""
:httpc.request(method, {erl_url, erl_headers, content_type, body}, http_opts, opts)
end
case result do
{:ok, {{_http_version, status, _reason_phrase}, resp_headers, resp_body}} ->
{:ok,
%{
status: status,
headers: Enum.map(resp_headers, fn {k, v} -> {to_string(k), to_string(v)} end),
body: to_string(resp_body)
}}
{:error, {:failed_connect, _} = reason} ->
{:error, reason}
{:error, :timeout} ->
{:error, {:timeout, :timeout}}
{:error, reason} ->
{:error, reason}
end
end
defp content_type_of(headers) do
headers
|> Enum.find_value(~c"application/octet-stream", fn {k, v} ->
if String.downcase(k) == "content-type", do: String.to_charlist(v)
end)
end
end