-
Notifications
You must be signed in to change notification settings - Fork 347
Home
Nicolás Garnil edited this page Mar 23, 2018
·
18 revisions
Pass Phoenix x-request-id header to upstream resources (by @timbuchwaldt)
defmodule MyAPI do
use Tesla
plug Tesla.Middleware.BaseUrl, "http://127.0.0.1:4000"
def foo(client, login) do
get(client, "/foo")
end
def client(%{resp_headers: resp_headers}) do
{"x-request-id", id} = resp_headers
|> List.keyfind("x-request-id", 0)
Tesla.build_client [
{PhoenixRequestIDMiddleware, id}
]
end
end
defmodule PhoenixRequestIDMiddleware do
def call(env, next, opts) do
env
|> add_request_id(opts)
|> IO.inspect
|> Tesla.run(next)
end
def add_request_id(env, id) do
Map.update!(env, :headers, &Map.merge(&1, %{"x-request-id" => id}))
end
end
defmodule Tesla.Middleware.Appsignal do
import Appsignal.Instrumentation.Helpers, only: [instrument: 3]
def call(env, next, _opts) do
verb = env.method |> to_string |> String.upcase
instrument "net.http", "#{verb} #{env.url}", fn ->
Tesla.run(env, next)
end
end
end
Sometimes you may need to do something with the url template (like sending metrics) before the path is replaced with the path parameters.
Usage:
defmodule MyAPI do
use Tesla
plug Tesla.Middleware.BaseUrl, "http://example.com"
plug MyAPI.Middleware.UrlBuilder
def get_user(user_id) do
get("/user/:id", opts: [params: [id: user_id]])
end
end
Middleware:
defmodule MyAPI.Middleware.UrlBuilder do
@moduledoc """
Builds the request url
"""
@behaviour Tesla.Middleware
@impl Tesla.Middleware
def call(env, next, _) do
url = build_url(env.url, env.opts[:params])
opts = Keyword.merge(env.opts, url: env.url)
Tesla.run(%{env | url: url, opts: opts}, next)
end
defp build_url(url, nil), do: url
defp build_url(url, params) do
Enum.reduce(params, url, fn {k, v}, u ->
String.replace(u, ":#{k}", to_string(v))
end)
end
end
Decode response as a struct.
Usage:
defmodule MyAPI do
use Tesla
plug Tesla.Middleware.BaseUrl, "http://example.com"
plug MyAPI.Middleware.DecodeJsonAs
def get_user(user_id) do
get("/user/" <> user_id, opts: [decode_as: %User{}])
end
end
Middleware:
defmodule MyApp.Middleware.DecodeJsonAs do
@moduledoc """
Decodes JSON response conveniently
"""
alias Tesla.Env
@behaviour Tesla.Middleware
@impl Tesla.Middleware
def call(env, next, _) do
decode(Tesla.run(env, next), env.opts[:decode_as])
end
defp decode({:ok, %Env{status: status, body: body}}, as) when status in 200..299 do
case body do
"" ->
{:ok, nil}
body ->
Poison.decode(body, as: as)
end
end
defp decode({:ok, %Env{body: ""} = env}, _), do: {:error, %Env{env | body: %{}}}
defp decode({:ok, %Env{body: body} = env}, _) do
with {:ok, body} <- Poison.decode(body) do
{:error, %Env{env | body: body}}
end
end
defp decode(error, _), do: error
end