Middleware for the Tesla HTTP client that sets value for HTTP headers dynamically at runtime from the application environment.
For example:
plug Tesla.Middleware.DynamicHeaders, [
# Set header with Application.get_env(:my_app, :foo_token)
{"X-Foo-Token", {:my_app, :foo_token}},
# Set header with Application.get_env(:my_app, :foo_token, "default")
{"X-Bar-Token", {:my_app, :bar_token, "default"}},
# Set value with a function
{"Authorization", &get_authorization/1},
# Set a static value
{"content/type", "application/json"}
]
defp get_authorization(header_name) do
"token: " <> Application.get_env(@app, :auth_token)
end
This is most useful to handle secrets such as auth tokens. If you set secrets at compile time, then they are hard coded into the release binaries, a security risk. Similarly, if you build your code in a CI system, then you have to make the secrets available there.
Instead, set values in the application environment from OS environment
variables in config/runtime.exs
:
config :my_app,
foo_token: System.get_env("FOO_TOKEN") || raise "missing environment variable FOO_TOKEN"
Add tesla_middleware_dynamic_headers
to the list of dependencies in mix.exs
:
def deps do
[
{:tesla_middleware_dynamic_headers, "~> 0.7.0"}
]
end
Add plug Tesla.Middleware.DynamicHeaders
to the client and specify a list
of headers.
The plug takes a single argument, either a list of tuples or a function. The first element of the tuple is the header name. Other values are as follows:
{application, key}
: Read the value fromApplication.get_env/2
{application, key, default}
: Read the value fromApplication.get_env/3
- Function with arity 1: Call the function with the header name to get the value
- Any other value is passed through as is, same as
Tesla.Middleware.Headers
If the argument is a zero-arity function, it is called to generate a list of
{header_name, value}
tuples.
The following example shows configuration via a list of headers:
defmodule FooClient do
use Tesla
@app :foo_client
plug Tesla.Middleware.BaseUrl, "https://example.com/"
plug Tesla.Middleware.DynamicHeaders, [
{"X-Foo-Token", {@app, :foo_token}},
{"X-Bar-Token", {@app, :bar_token, "default"}},
{"Authorization", &get_authorization/1},
{"content/type", "application/json"}
]
plug Tesla.Middleware.Logger
defp get_authorization(header_name) do
"token: " <> Application.get_env(@app, :auth_token)
end
end
The following example uses a custom function to generate all the headers:
defmodule FooClient do
use Tesla
@app :foo_client
plug Tesla.Middleware.DynamicHeaders, &get_dynamic_headers/0
defp get_dynamic_headers do
Application.get_env(@app, :headers)
end
end
The app configuration in config/test.exs
might look like:
config :foo_client,
foo_token: "footoken",
bar_token: "bartoken",
auth_token: "authtoken"
config :foo_client,
headers: [
{"Authorization", "token: authtoken"}
]
In production, you would normally set environment variables with the tokens
then read them in config/runtime.exs
:
config :foo_client,
foo_token: System.get_env("FOO_TOKEN") || raise "missing environment variable FOO_TOKEN"
Documentation is here: https://hexdocs.pm/tesla_middleware_dynamic_headers
This project uses the Contributor Covenant version 2.1. Check CODE_OF_CONDUCT.md for more information.
I am jakemorrison
on on the Elixir Slack and Discord, reachfh
on Freenode
#elixir-lang
IRC channel. Happy to chat or help with your projects.