Skip to content

Commit

Permalink
Merge 5d9819c into 38aa74e
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt committed Jul 9, 2019
2 parents 38aa74e + 5d9819c commit 3710b5c
Show file tree
Hide file tree
Showing 28 changed files with 237 additions and 215 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
8 changes: 4 additions & 4 deletions .travis.yml
Expand Up @@ -3,12 +3,11 @@ language: elixir
sudo: false

elixir:
- '1.4.5'
- '1.5.3'
- '1.6.1'
- '1.8.2'
- '1.9.0'

otp_release:
- '20.0'
- '22.0'

env:
- MIX_ENV="test"
Expand All @@ -18,6 +17,7 @@ script:
- mix coveralls.travis --max-cases 1
- mix credo
- mix dialyzer --halt-exit-status
- mix format --check-formatted

cache:
directories:
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Expand Up @@ -16,4 +16,5 @@ Make sure you have Elixir 1.4 or greater installed. Copy and paste the following
4. Push to the branch (`git push origin my-new-feature`).
5. Make sure the tests pass (`mix coveralls.html`).
6. Open up `cover/excoveralls.html` in your browser and add tests if required to meet the minimum coverage threshold.
7. Create new Pull Request.
7. Make sure the code is formatted (`mix format`).
8. Create new Pull Request.
2 changes: 1 addition & 1 deletion config/config.exs
@@ -1,3 +1,3 @@
use Mix.Config

import_config "#{Mix.env}.exs"
import_config "#{Mix.env()}.exs"
1 change: 0 additions & 1 deletion lib/lob/address.ex
Expand Up @@ -4,5 +4,4 @@ defmodule Lob.Address do
"""

use Lob.ResourceBase, endpoint: "addresses", methods: [:create, :retrieve, :list, :delete]

end
3 changes: 1 addition & 2 deletions lib/lob/bank_account.ex
Expand Up @@ -5,11 +5,10 @@ defmodule Lob.BankAccount do

use Lob.ResourceBase, endpoint: "bank_accounts", methods: [:create, :retrieve, :list, :delete]

@spec verify(String.t, map, map) :: Client.client_response
@spec verify(String.t(), map, map) :: Client.client_response()
def verify(id, data, headers \\ %{}) do
Client.post_request(verify_url(id), Util.build_body(data), Util.build_headers(headers))
end

defp verify_url(resource_id), do: "#{resource_url(resource_id)}/verify"

end
1 change: 0 additions & 1 deletion lib/lob/check.ex
Expand Up @@ -4,5 +4,4 @@ defmodule Lob.Check do
"""

use Lob.ResourceBase, endpoint: "checks", methods: [:create, :retrieve, :list, :delete]

end
41 changes: 23 additions & 18 deletions lib/lob/client.ex
Expand Up @@ -9,7 +9,7 @@ defmodule Lob.Client do

use HTTPoison.Base

@client_version Mix.Project.config[:version]
@client_version Mix.Project.config()[:version]

@type client_response :: {:ok, map, list} | {:error, map}

Expand All @@ -19,27 +19,28 @@ defmodule Lob.Client do
"""

defexception message: """
The api_key setting is required to make requests to Lob.
Please configure :api_key in config.exs or set the LOB_API_KEY
environment variable.
The api_key setting is required to make requests to Lob.
Please configure :api_key in config.exs or set the LOB_API_KEY
environment variable.
config :lob_elixir, api_key: API_KEY
"""
config :lob_elixir, api_key: API_KEY
"""
end

@spec client_version :: String.t
@spec client_version :: String.t()
def client_version, do: @client_version

@spec api_key(atom) :: String.t
@spec api_key(atom) :: String.t()
def api_key(env_key \\ :api_key) do
case Application.get_env(:lob_elixir, env_key, System.get_env("LOB_API_KEY")) || :not_found do
:not_found -> raise MissingAPIKeyError
value -> value
end
end

@spec api_version :: String.t | nil
def api_version, do: Application.get_env(:lob_elixir, :api_version, System.get_env("LOB_API_VERSION"))
@spec api_version :: String.t() | nil
def api_version,
do: Application.get_env(:lob_elixir, :api_version, System.get_env("LOB_API_VERSION"))

# #########################
# HTTPoison.Base callbacks
Expand All @@ -60,21 +61,21 @@ defmodule Lob.Client do
# Client API
# #########################

@spec get_request(String.t, HTTPoison.Base.headers) :: client_response
@spec get_request(String.t(), HTTPoison.Base.headers()) :: client_response
def get_request(url, headers \\ []) do
url
|> get(headers, build_options())
|> handle_response
end

@spec post_request(String.t, {:multipart, list}, HTTPoison.Base.headers) :: client_response
@spec post_request(String.t(), {:multipart, list}, HTTPoison.Base.headers()) :: client_response
def post_request(url, body, headers \\ []) do
url
|> post(body, headers, build_options())
|> handle_response
end

@spec delete_request(String.t, HTTPoison.Base.headers) :: client_response
@spec delete_request(String.t(), HTTPoison.Base.headers()) :: client_response
def delete_request(url, headers \\ []) do
url
|> delete(headers, build_options())
Expand All @@ -85,9 +86,9 @@ defmodule Lob.Client do
# Response handlers
# #########################

@spec handle_response({:ok | :error, Response.t | Error.t}) :: client_response
@spec handle_response({:ok | :error, Response.t() | Error.t()}) :: client_response
defp handle_response({:ok, %{body: body, headers: headers, status_code: code}})
when code >= 200 and code < 300 do
when code >= 200 and code < 300 do
{:ok, body, headers}
end

Expand All @@ -99,13 +100,17 @@ defmodule Lob.Client do
{:error, %{message: Error.message(error)}}
end

@spec build_options(String.t) :: Keyword.t
@spec build_options(String.t()) :: Keyword.t()
defp build_options(api_key \\ api_key()) do
[hackney: [basic_auth: {api_key, ""}], recv_timeout: :infinity]
end

@spec default_headers(String.t | nil) :: %{String.t => String.t}
@spec default_headers(String.t() | nil) :: %{String.t() => String.t()}
defp default_headers(nil), do: %{"User-Agent" => "Lob/v1 ElixirBindings/#{client_version()}"}
defp default_headers(api_version), do: %{"User-Agent" => "Lob/v1 ElixirBindings/#{client_version()}", "Lob-Version" => api_version}

defp default_headers(api_version),
do: %{
"User-Agent" => "Lob/v1 ElixirBindings/#{client_version()}",
"Lob-Version" => api_version
}
end
3 changes: 1 addition & 2 deletions lib/lob/intl_verification.ex
Expand Up @@ -5,9 +5,8 @@ defmodule Lob.IntlVerification do

use Lob.ResourceBase, endpoint: "intl_verifications", methods: []

@spec verify(map, map) :: Client.client_response
@spec verify(map, map) :: Client.client_response()
def verify(data, headers \\ %{}) do
Client.post_request(base_url(), Util.build_body(data), Util.build_headers(headers))
end

end
1 change: 0 additions & 1 deletion lib/lob/letter.ex
Expand Up @@ -4,5 +4,4 @@ defmodule Lob.Letter do
"""

use Lob.ResourceBase, endpoint: "letters", methods: [:create, :retrieve, :list, :delete]

end
1 change: 0 additions & 1 deletion lib/lob/postcard.ex
Expand Up @@ -4,5 +4,4 @@ defmodule Lob.Postcard do
"""

use Lob.ResourceBase, endpoint: "postcards", methods: [:create, :retrieve, :list, :delete]

end
25 changes: 13 additions & 12 deletions lib/lob/resource_base.ex
Expand Up @@ -14,9 +14,12 @@ defmodule Lob.ResourceBase do
alias Lob.Client

if :list in unquote(methods) do
@spec list(map, map) :: Client.client_response
@spec list(map, map) :: Client.client_response()
def list(params \\ %{}, headers \\ %{}) do
Client.get_request("#{base_url()}?#{Util.build_query_string(params)}" , Util.build_headers(headers))
Client.get_request(
"#{base_url()}?#{Util.build_query_string(params)}",
Util.build_headers(headers)
)
end

@spec list!(map, map) :: {map, list} | no_return
Expand All @@ -29,12 +32,12 @@ defmodule Lob.ResourceBase do
end

if :retrieve in unquote(methods) do
@spec retrieve(String.t, map) :: Client.client_response
@spec retrieve(String.t(), map) :: Client.client_response()
def retrieve(id, headers \\ %{}) do
Client.get_request(resource_url(id), Util.build_headers(headers))
end

@spec retrieve!(String.t, map) :: {map, list} | no_return
@spec retrieve!(String.t(), map) :: {map, list} | no_return
def retrieve!(id, headers \\ %{}) do
case retrieve(id, headers) do
{:ok, body, headers} -> {body, headers}
Expand All @@ -44,7 +47,7 @@ defmodule Lob.ResourceBase do
end

if :create in unquote(methods) do
@spec create(map, map) :: Client.client_response
@spec create(map, map) :: Client.client_response()
def create(data, headers \\ %{}) do
Client.post_request(base_url(), Util.build_body(data), Util.build_headers(headers))
end
Expand All @@ -59,12 +62,12 @@ defmodule Lob.ResourceBase do
end

if :delete in unquote(methods) do
@spec delete(String.t, map) :: Client.client_response
@spec delete(String.t(), map) :: Client.client_response()
def delete(id, headers \\ %{}) do
Client.delete_request(resource_url(id), Util.build_headers(headers))
end

@spec delete!(String.t, map) :: {map, list} | no_return
@spec delete!(String.t(), map) :: {map, list} | no_return
def delete!(id, headers \\ %{}) do
case delete(id, headers) do
{:ok, body, headers} -> {body, headers}
Expand All @@ -73,16 +76,14 @@ defmodule Lob.ResourceBase do
end
end

@spec base_url :: String.t
@spec base_url :: String.t()
defp base_url, do: "#{api_host()}/#{unquote(endpoint)}"

@spec api_host :: String.t
@spec api_host :: String.t()
defp api_host, do: Application.get_env(:lob_elixir, :api_host, @default_api_host)

@spec resource_url(String.t) :: String.t
@spec resource_url(String.t()) :: String.t()
defp resource_url(resource_id), do: "#{base_url()}/#{resource_id}"
end

end

end
2 changes: 1 addition & 1 deletion lib/lob/us_autocompletion.ex
Expand Up @@ -5,7 +5,7 @@ defmodule Lob.USAutocompletion do

use Lob.ResourceBase, endpoint: "us_autocompletions", methods: []

@spec autocomplete(map, map) :: Client.client_response
@spec autocomplete(map, map) :: Client.client_response()
def autocomplete(data, headers \\ %{}) do
Client.post_request(base_url(), Util.build_body(data), Util.build_headers(headers))
end
Expand Down
3 changes: 1 addition & 2 deletions lib/lob/us_verification.ex
Expand Up @@ -5,9 +5,8 @@ defmodule Lob.USVerification do

use Lob.ResourceBase, endpoint: "us_verifications", methods: []

@spec verify(map, map) :: Client.client_response
@spec verify(map, map) :: Client.client_response()
def verify(data, headers \\ %{}) do
Client.post_request(base_url(), Util.build_body(data), Util.build_headers(headers))
end

end
3 changes: 1 addition & 2 deletions lib/lob/us_zip_lookup.ex
Expand Up @@ -5,9 +5,8 @@ defmodule Lob.USZipLookup do

use Lob.ResourceBase, endpoint: "us_zip_lookups", methods: []

@spec lookup(map, map) :: Client.client_response
@spec lookup(map, map) :: Client.client_response()
def lookup(data, headers \\ %{}) do
Client.post_request(base_url(), Util.build_body(data), Util.build_headers(headers))
end

end
6 changes: 3 additions & 3 deletions lib/lob/util.ex
Expand Up @@ -10,7 +10,7 @@ defmodule Lob.Util do
iex> Lob.Util.build_query_string(%{count: 1, include: ["total_count"], metadata: %{name: "Larry"}})
"count=1&include%5B%5D=total_count&metadata%5Bname%5D=Larry"
"""
@spec build_query_string(map) :: String.t
@spec build_query_string(map) :: String.t()
def build_query_string(params) when is_map(params) do
params
|> Enum.reduce([], &(&2 ++ transform_argument(&1)))
Expand Down Expand Up @@ -38,10 +38,10 @@ defmodule Lob.Util do
iex> Lob.Util.build_headers(%{"Idempotency-Key" => "abc123", "Lob-Version" => "2017-11-08"})
[{"Idempotency-Key", "abc123"}, {"Lob-Version", "2017-11-08"}]
"""
@spec build_headers(map) :: HTTPoison.Base.headers
@spec build_headers(map) :: HTTPoison.Base.headers()
def build_headers(headers) do
headers
|> Enum.to_list
|> Enum.to_list()
|> Enum.map(fn {k, v} -> {to_string(k), to_string(v)} end)
end

Expand Down
4 changes: 2 additions & 2 deletions mix.exs
Expand Up @@ -5,9 +5,9 @@ defmodule Lob.Mixfile do
[
app: :lob_elixir,
version: "1.1.1",
elixir: "~> 1.4",
elixir: "~> 1.8",
preferred_cli_env: ["coveralls.html": :test],
start_permanent: Mix.env == :prod,
start_permanent: Mix.env() == :prod,
test_coverage: [tool: ExCoveralls],
description: "Lob Elixir Library",
package: package(),
Expand Down
11 changes: 1 addition & 10 deletions test/lob/address_test.exs
Expand Up @@ -19,7 +19,6 @@ defmodule Lob.AddressTest do
end

describe "list/2" do

test "lists addresses" do
{:ok, addresses, _headers} = Address.list()
assert addresses.object == "list"
Expand All @@ -39,22 +38,18 @@ defmodule Lob.AddressTest do
{:ok, addresses, _headers} = Address.list(%{metadata: %{foo: "bar"}})
assert addresses.count == 1
end

end

describe "retrieve/2" do

test "retrieves an address", %{sample_address: sample_address} do
{:ok, created_address, _headers} = Address.create(sample_address)

{:ok, retrieved_address, _headers} = Address.retrieve(created_address.id)
assert retrieved_address.name == created_address.name
end

end

describe "create/2" do

test "creates an address", %{sample_address: sample_address} do
{:ok, created_address, headers} = Address.create(sample_address)

Expand All @@ -66,24 +61,20 @@ defmodule Lob.AddressTest do
{:ok, created_address, headers} =
sample_address
|> Map.merge(%{metadata: %{key: "value"}})
|> Address.create
|> Address.create()

assert created_address.name == String.upcase(sample_address.name)
assert Enum.member?(headers, {"X-Rate-Limit-Limit", "150"})
end

end

describe "delete/2" do

test "deletes an address", %{sample_address: sample_address} do
{:ok, created_address, _headers} = Address.create(sample_address)

{:ok, deleted_address, _headers} = Address.delete(created_address.id)
assert deleted_address.id == created_address.id
assert deleted_address.deleted == true
end

end

end

0 comments on commit 3710b5c

Please sign in to comment.