Skip to content
This repository was archived by the owner on Sep 1, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,44 @@ job = %{
credentials = %Credentials{client_id: "...", client_secret: "..."}
StuartClientElixir.post("/v2/jobs", Jason.encode!(job), %{environment: Environment.sandbox(), credentials: credentials})
```

#### Send a PATCH request to the Stuart API

```elixir
alias StuartClientElixir.{Environment, Credentials}

job = %{
job: %{
deliveries: [
%{
id: "43035",
client_reference: "new_client_reference",
package_description: "new_package_description",
pickup: %{
comment: "new_comment",
contact: %{
firstname: "new_firstname",
lastname: "new_lastname",
phone: "+33628046091",
email: "sd@df.com",
company: "new_company"
}
},
dropoff: %{
comment: "new_comment",
contact: %{
firstname: "new_firstname",
lastname: "new_lastname",
phone: "+33628046095",
email: "new_email@mymail.com",
company: "new_company"
}
}
}
]
}
}

credentials = %Credentials{client_id: "...", client_secret: "..."}
StuartClientElixir.patch("/v2/jobs/1234", Jason.encode!(job), %{environment: Environment.sandbox(), credentials: credentials})
```
1 change: 1 addition & 0 deletions lib/stuart_client_elixir.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ defmodule StuartClientElixir do

defdelegate get(resource, options), to: HttpClient
defdelegate post(resource, body, options), to: HttpClient
defdelegate patch(resource, body, options), to: HttpClient
defdelegate forget_token!(client_id), to: Authenticator
end
46 changes: 30 additions & 16 deletions lib/stuart_client_elixir/http_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,49 @@ defmodule StuartClientElixir.HttpClient do

@callback get(url, options) :: ok_response | error_response
@callback post(url, body, options) :: ok_response | error_response
@callback patch(url, body, options) :: ok_response | error_response

def get(resource, %{environment: environment, credentials: credentials}) do
with url <- url(resource, environment),
{:ok, access_token} <- Authenticator.access_token(environment, credentials),
headers <- default_headers(access_token) do
HTTPoison.get(url, headers, default_options())
|> to_api_response()
else
{:error, %OAuth2.Response{}} = oauth_response -> to_api_response(oauth_response)
{:error, %OAuth2.Error{}} = oauth_error -> to_api_response(oauth_error)
end
def get(resource, options) do
perform_request(:get, options, resource)
end

def post(resource, body, options) do
perform_request(:post, options, resource, body)
end

def post(resource, body, %{environment: environment, credentials: credentials}) do
def patch(resource, body, options) do
perform_request(:patch, options, resource, body)
end

#####################
# Private functions #
#####################

def perform_request(
method,
%{
environment: environment,
credentials: credentials
},
resource,
body \\ nil
)
when method in [:get, :post, :patch] do
with url <- url(resource, environment),
{:ok, access_token} <- Authenticator.access_token(environment, credentials),
headers <- default_headers(access_token) do
HTTPoison.post(url, body, headers, default_options())
case method do
:get -> HTTPoison.get(url, headers, default_options())
:post -> HTTPoison.post(url, body, headers, default_options())
:patch -> HTTPoison.patch(url, body, headers, default_options())
end
|> to_api_response()
else
{:error, %OAuth2.Response{}} = oauth_response -> to_api_response(oauth_response)
{:error, %OAuth2.Error{}} = oauth_error -> to_api_response(oauth_error)
end
end

#####################
# Private functions #
#####################

defp default_options do
[recv_timeout: 10_000]
end
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule StuartClientElixir.MixProject do
}
},
version: "1.2.0",
elixir: "~> 1.7",
elixir: "~> 1.6",
start_permanent: Mix.env() == :prod,
deps: deps()
]
Expand Down
60 changes: 50 additions & 10 deletions test/stuart_client_elixir/http_client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ defmodule StuartClientElixirTest.HttpClientTest do
[],
[
get: fn url, _headers, _options -> response(:get, url) end,
post: fn url, _body, _headers, _options -> response(:post, url) end
post: fn url, _body, _headers, _options -> response(:post, url) end,
patch: fn url, _body, _headers, _options -> response(:patch, url) end
]
}
]) do
Expand All @@ -41,7 +42,7 @@ defmodule StuartClientElixirTest.HttpClientTest do

describe "get" do
test "calls HTTPoison with correct parameters" do
expected_response = %{body: %{"sample" => "get response"}, status_code: 201}
expected_response = %{body: %{"sample" => "get response"}, status_code: 200}

assert HttpClient.get("/sample-endpoint", config()) == expected_response

Expand All @@ -63,8 +64,7 @@ defmodule StuartClientElixirTest.HttpClientTest do
test "returns explicit error when authentication fails because of other OAuth error" do
expected_response = {:error, oauth2_error()}

assert HttpClient.get("/sample-endpoint", config(@oauth_error)) ==
expected_response
assert HttpClient.get("/sample-endpoint", config(@oauth_error)) == expected_response
end

test "returns explicit error when GET request fails" do
Expand Down Expand Up @@ -112,26 +112,66 @@ defmodule StuartClientElixirTest.HttpClientTest do
end
end

describe "patch" do
test "calls HTTPoison with correct parameters" do
expected_response = %{body: %{"sample" => "patch response"}, status_code: 200}

assert HttpClient.patch("/sample-endpoint", sample_request_body(), config()) ==
expected_response

assert called(
HTTPoison.patch(
"https://sandbox-api.stuart.com/sample-endpoint",
sample_request_body(),
expected_headers(),
expected_options()
)
)
end

test "returns explicit error when authentication fails because of bad credentials" do
expected_response = %{body: %{"error" => "Bad credentials"}, status_code: 401}

assert HttpClient.patch("/sample-endpoint", sample_request_body(), config(@bad_credentials)) ==
expected_response
end

test "returns explicit error when authentication fails because of other OAuth error" do
expected_response = {:error, oauth2_error()}

assert HttpClient.patch("/sample-endpoint", sample_request_body(), config(@oauth_error)) ==
expected_response
end

test "returns explicit error when PATCH request fails" do
expected_response = {:error, %HTTPoison.Error{id: nil, reason: :timeout}}

assert HttpClient.patch("/timeout", sample_request_body(), config()) == expected_response
end
end

#####################
# Private functions #
#####################

defp response(:get, "https://sandbox-api.stuart.com/timeout") do
@timeout_url "https://sandbox-api.stuart.com/timeout"

defp response(_, @timeout_url) do
{:error, %HTTPoison.Error{id: nil, reason: :timeout}}
end

defp response(:get, _) do
{:ok, %HTTPoison.Response{status_code: 201, body: Jason.encode!(%{sample: "get response"})}}
end

defp response(:post, "https://sandbox-api.stuart.com/timeout") do
{:error, %HTTPoison.Error{id: nil, reason: :timeout}}
{:ok, %HTTPoison.Response{status_code: 200, body: Jason.encode!(%{sample: "get response"})}}
end

defp response(:post, _) do
{:ok, %HTTPoison.Response{status_code: 201, body: Jason.encode!(%{sample: "post response"})}}
end

defp response(:patch, _) do
{:ok, %HTTPoison.Response{status_code: 200, body: Jason.encode!(%{sample: "patch response"})}}
end

defp authenticator_response(@good_credentials) do
{:ok, "sample-access-token"}
end
Expand Down