From 226051be588f14787d08bdd58f82fdba66ca9aee Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Sat, 12 Mar 2022 10:36:00 +0200 Subject: [PATCH] Add Client.update_middleware/2 function A typical use-case is the following: A third-party library (i.e GitHub) exposes a function that returns a Tesla client, but I want to append a header or add logging/telemetry to it. I need to write a wrapper for Tesla.Client.middleware/1 and Tesla.client/2. --- lib/tesla/client.ex | 19 +++++++++++++++++++ test/tesla/client_test.exs | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/tesla/client.ex b/lib/tesla/client.ex index a120075c..74afcd44 100644 --- a/lib/tesla/client.ex +++ b/lib/tesla/client.ex @@ -43,6 +43,25 @@ defmodule Tesla.Client do unruntime(client.pre) end + @doc ~S""" + Given an update function, create a new client by transforming the + list of middlewares for an existing one. + + ## Examples + + iex> middleware = [{Tesla.Middleware.BaseUrl, "https://api.github.com"}] + iex> client = Tesla.client(middleware) + iex> new_client = Tesla.Client.update_middleware(client, &([Tesla.Middleware.JSON] ++ &1)) + iex> Tesla.Client.middleware(new_client) + [Tesla.Middleware.JSON, {Tesla.Middleware.BaseUrl, "https://api.github.com"}] + """ + @spec update_middleware(t(), ([middleware()] -> [middleware()])) :: t() + def update_middleware(client, update_fun) do + existing_middleware = middleware(client) + new_middleware = update_fun.(existing_middleware) + Tesla.client(new_middleware, adapter(client)) + end + defp unruntime(list) when is_list(list), do: Enum.map(list, &unruntime/1) defp unruntime({module, :call, [[]]}) when is_atom(module), do: module defp unruntime({module, :call, [opts]}) when is_atom(module), do: {module, opts} diff --git a/test/tesla/client_test.exs b/test/tesla/client_test.exs index 75ae161f..7fb31696 100644 --- a/test/tesla/client_test.exs +++ b/test/tesla/client_test.exs @@ -49,4 +49,21 @@ defmodule Tesla.ClientTest do assert middlewares == Tesla.Client.middleware(client) end end + + describe "Tesla.Client.update_middleware/2" do + test "updates middleware" do + existing_middleware = [FirstMiddleware] + client = Tesla.client(existing_middleware) + + updated_client = + Tesla.Client.update_middleware( + client, + &([{SecondMiddleware, options: :are, fun: 1}] ++ &1) + ) + + expected_middlewares = [{SecondMiddleware, options: :are, fun: 1}, FirstMiddleware] + + assert expected_middlewares == Tesla.Client.middleware(updated_client) + end + end end