A HTTP toolkit for building API clients using middlewares.
Building API client
Use Tesla.client/2 to build a client with the given middleware and adapter.
Examples
defmodule ExampleApi do
def client do
Tesla.client([
{Tesla.Middleware.BaseUrl, "http://api.example.com"},
Tesla.Middleware.JSON
])
end
def fetch_data(client) do
Tesla.get(client, "/data")
end
endNow you can use ExampleApi.client/0 to make requests to the API.
client = ExampleApi.client()
ExampleApi.fetch_data(client)Direct usage
It is also possible to do request directly with Tesla module.
Tesla.get("https://example.com")Default adapter
By default Tesla is using Tesla.Adapter.Httpc, because :httpc is
included in Erlang/OTP and does not require installation of any additional
dependency. It can be changed globally with config:
config :tesla, :adapter, Tesla.Adapter.MintAssigns and Private
Tesla.Env has two map fields for storing additional data: :assigns and :private.
:assigns is a place for user data. It can be used to carry application-specific metadata
through the middleware pipeline.
:private is a map reserved for libraries and middleware to use. The keys must be atoms.
Prefix the keys with the name of your project to avoid any future conflicts. The tesla_
prefix is reserved for Tesla.
Summary
Functions
Builds a URL from the given Tesla.Env.t/0 struct.
Builds URL with the given URL and query params.
Dynamically build client from list of middlewares and/or adapter.
Perform a DELETE request.
Perform a DELETE request.
Perform a GET request.
Perform a GET request.
Returns value of header specified by key from :headers field in Tesla.Env.
Perform a HEAD request.
Perform a HEAD request.
Perform a OPTIONS request.
Perform a OPTIONS request.
Perform a PATCH request.
Perform a PATCH request.
Perform a POST request.
Perform a POST request.
Perform a PUT request.
Perform a PUT request.
Assigns key/value to Tesla.Env.
Assigns key/value to Tesla.Env unless the key is already set.
Merges the given assigns into Tesla.Env.
Adds given key/value pair to :opts field in Tesla.Env.
Perform a request.
Perform request and raise in case of error.
Perform a TRACE request.
Perform a TRACE request.
Updates assign key in Tesla.Env with the given function or default.
Updates assign key in Tesla.Env with the given function.
Types
@type encoding_strategy() :: :rfc3986 | :www_form
@type option() :: {:method, Tesla.Env.method()} | {:url, Tesla.Env.url()} | {:query, Tesla.Env.query()} | {:headers, Tesla.Env.headers()} | {:body, Tesla.Env.body()} | {:opts, Tesla.Env.opts()}
Options that may be passed to a request function. See request/2 for detailed descriptions.
Functions
@spec build_url(Tesla.Env.t()) :: String.t()
Builds a URL from the given Tesla.Env.t/0 struct.
Combines the url and query fields, and allows specifying the encoding
strategy before calling build_url/3.
@spec build_url(Tesla.Env.url(), Tesla.Env.query(), encoding_strategy()) :: binary()
Builds URL with the given URL and query params.
Useful when you need to create a URL with dynamic query params from a Keyword list
Allows to specify the encoding strategy to be one either :www_form or
:rfc3986. Read more about encoding at URI.encode_query/2.
url- the base URL to which the query params will be appended.query- a list of key-value pairs to be encoded as query params.encoding- the encoding strategy to use. Defaults to:www_form
Examples
iex> Tesla.build_url("https://api.example.com", [user: 3, page: 2])
"https://api.example.com?user=3&page=2"URL that already contains query params:
iex> url = "https://api.example.com?user=3"
iex> Tesla.build_url(url, [page: 2, status: true])
"https://api.example.com?user=3&page=2&status=true"Default encoding :www_form:
iex> Tesla.build_url("https://api.example.com", [user_name: "John Smith"])
"https://api.example.com?user_name=John+Smith"Specified encoding strategy :rfc3986:
iex> Tesla.build_url("https://api.example.com", [user_name: "John Smith"], :rfc3986)
"https://api.example.com?user_name=John%20Smith"
@spec client([Tesla.Client.middleware()], Tesla.Client.adapter()) :: Tesla.Client.t()
Dynamically build client from list of middlewares and/or adapter.
# add dynamic middleware
client = Tesla.client([{Tesla.Middleware.Headers, [{"authorization", token}]}])
Tesla.get(client, "/path")
# configure adapter in runtime
client = Tesla.client([], Tesla.Adapter.Hackney)
client = Tesla.client([], {Tesla.Adapter.Hackney, pool: :my_pool})
Tesla.get(client, "/path")
# complete module example
defmodule MyApi do
@middleware [
{Tesla.Middleware.BaseUrl, "https://example.com"},
Tesla.Middleware.JSON,
Tesla.Middleware.Logger
]
@adapter Tesla.Adapter.Hackney
def new(opts) do
# do any middleware manipulation you need
middleware = [
{Tesla.Middleware.BasicAuth, username: opts[:username], password: opts[:password]}
] ++ @middleware
# allow configuring adapter in runtime
adapter = opts[:adapter] || @adapter
# use Tesla.client/2 to put it all together
Tesla.client(middleware, adapter)
end
def get_something(client, id) do
# pass client directly to Tesla.get/2
Tesla.get(client, "/something/#{id}")
# ...
end
end
client = MyApi.new(username: "admin", password: "secret")
MyApi.get_something(client, 42)
@spec delete(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()
Perform a DELETE request.
See request/1 or request/2 for options definition.
delete("/users")
delete("/users", query: [scope: "admin"])
delete(client, "/users")
delete(client, "/users", query: [scope: "admin"])
delete(client, "/users", body: %{name: "Jon"})
@spec delete!(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.t() | no_return()
Perform a DELETE request.
See request!/1 or request!/2 for options definition.
delete!("/users")
delete!("/users", query: [scope: "admin"])
delete!(client, "/users")
delete!(client, "/users", query: [scope: "admin"])
delete!(client, "/users", body: %{name: "Jon"})
@spec delete_header(Tesla.Env.t(), binary()) :: Tesla.Env.t()
@spec get(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()
Perform a GET request.
See request/1 or request/2 for options definition.
get("/users")
get("/users", query: [scope: "admin"])
get(client, "/users")
get(client, "/users", query: [scope: "admin"])
get(client, "/users", body: %{name: "Jon"})
@spec get!(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.t() | no_return()
Perform a GET request.
See request!/1 or request!/2 for options definition.
get!("/users")
get!("/users", query: [scope: "admin"])
get!(client, "/users")
get!(client, "/users", query: [scope: "admin"])
get!(client, "/users", body: %{name: "Jon"})
@spec get_header(Tesla.Env.t(), binary()) :: binary() | nil
Returns value of header specified by key from :headers field in Tesla.Env.
Examples
# non existing header
iex> env = %Tesla.Env{headers: [{"server", "Cowboy"}]}
iex> Tesla.get_header(env, "some-key")
nil
# existing header
iex> env = %Tesla.Env{headers: [{"server", "Cowboy"}]}
iex> Tesla.get_header(env, "server")
"Cowboy"
# first of multiple headers with the same name
iex> env = %Tesla.Env{headers: [{"cookie", "chocolate"}, {"cookie", "biscuits"}]}
iex> Tesla.get_header(env, "cookie")
"chocolate"
@spec get_headers(Tesla.Env.t(), binary()) :: [binary()]
@spec head(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()
Perform a HEAD request.
See request/1 or request/2 for options definition.
head("/users")
head("/users", query: [scope: "admin"])
head(client, "/users")
head(client, "/users", query: [scope: "admin"])
head(client, "/users", body: %{name: "Jon"})
@spec head!(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.t() | no_return()
Perform a HEAD request.
See request!/1 or request!/2 for options definition.
head!("/users")
head!("/users", query: [scope: "admin"])
head!(client, "/users")
head!(client, "/users", query: [scope: "admin"])
head!(client, "/users", body: %{name: "Jon"})
@spec options(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()
Perform a OPTIONS request.
See request/1 or request/2 for options definition.
options("/users")
options("/users", query: [scope: "admin"])
options(client, "/users")
options(client, "/users", query: [scope: "admin"])
options(client, "/users", body: %{name: "Jon"})
@spec options!(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.t() | no_return()
Perform a OPTIONS request.
See request!/1 or request!/2 for options definition.
options!("/users")
options!("/users", query: [scope: "admin"])
options!(client, "/users")
options!(client, "/users", query: [scope: "admin"])
options!(client, "/users", body: %{name: "Jon"})
@spec patch(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.result()
Perform a PATCH request.
See request/1 or request/2 for options definition.
patch("/users", %{name: "Jon"})
patch("/users", %{name: "Jon"}, query: [scope: "admin"])
patch(client, "/users", %{name: "Jon"})
patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec patch!(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.t() | no_return()
Perform a PATCH request.
See request!/1 or request!/2 for options definition.
patch!("/users", %{name: "Jon"})
patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
patch!(client, "/users", %{name: "Jon"})
patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec post(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.result()
Perform a POST request.
See request/1 or request/2 for options definition.
post("/users", %{name: "Jon"})
post("/users", %{name: "Jon"}, query: [scope: "admin"])
post(client, "/users", %{name: "Jon"})
post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec post!(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.t() | no_return()
Perform a POST request.
See request!/1 or request!/2 for options definition.
post!("/users", %{name: "Jon"})
post!("/users", %{name: "Jon"}, query: [scope: "admin"])
post!(client, "/users", %{name: "Jon"})
post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec put(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.result()
Perform a PUT request.
See request/1 or request/2 for options definition.
put("/users", %{name: "Jon"})
put("/users", %{name: "Jon"}, query: [scope: "admin"])
put(client, "/users", %{name: "Jon"})
put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec put!(Tesla.Env.client(), Tesla.Env.url(), Tesla.Env.body(), [option()]) :: Tesla.Env.t() | no_return()
Perform a PUT request.
See request!/1 or request!/2 for options definition.
put!("/users", %{name: "Jon"})
put!("/users", %{name: "Jon"}, query: [scope: "admin"])
put!(client, "/users", %{name: "Jon"})
put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
@spec put_assign(Tesla.Env.t(), atom(), any()) :: Tesla.Env.t()
Assigns key/value to Tesla.Env.
Examples
iex> env = %Tesla.Env{}
iex> env = Tesla.put_assign(env, :user_id, 123)
iex> env.assigns
%{user_id: 123}
@spec put_assign_new(Tesla.Env.t(), atom(), any()) :: Tesla.Env.t()
Assigns key/value to Tesla.Env unless the key is already set.
Examples
iex> env = %Tesla.Env{}
iex> env = Tesla.put_assign_new(env, :user_id, 123)
iex> env = Tesla.put_assign_new(env, :user_id, 456)
iex> env.assigns
%{user_id: 123}
@spec put_assigns(Tesla.Env.t(), Tesla.Env.assigns()) :: Tesla.Env.t()
Merges the given assigns into Tesla.Env.
Examples
iex> env = %Tesla.Env{}
iex> env = Tesla.put_assigns(env, %{user_id: 123, role: :admin})
iex> env.assigns
%{user_id: 123, role: :admin}
iex> env = %Tesla.Env{assigns: %{user_id: 123}}
iex> env = Tesla.put_assigns(env, %{role: :admin})
iex> env.assigns
%{user_id: 123, role: :admin}
@spec put_body(Tesla.Env.t(), Tesla.Env.body()) :: Tesla.Env.t()
@spec put_header(Tesla.Env.t(), binary(), binary()) :: Tesla.Env.t()
@spec put_headers(Tesla.Env.t(), [{binary(), binary()}]) :: Tesla.Env.t()
@spec put_opt(Tesla.Env.t(), atom(), any()) :: Tesla.Env.t()
Adds given key/value pair to :opts field in Tesla.Env.
Useful when there's a need to store additional middleware data in Tesla.Env
Examples
iex> %Tesla.Env{opts: []} |> Tesla.put_opt(:option, "value")
%Tesla.Env{opts: [option: "value"]}
@spec request(Tesla.Env.client(), [option()]) :: Tesla.Env.result()
Perform a request.
Options
:method- the request method, one of [:head,:get,:delete,:trace,:options,:post,:put,:patch]:url- either full url e.g. "http://example.com/some/path" or just "/some/path" if usingTesla.Middleware.BaseUrl:query- a keyword list of query params, e.g.[page: 1, per_page: 100]:headers- a keyword list of headers, e.g.[{"content-type", "text/plain"}]:body- depends on used middleware:- by default it can be a binary
- if using e.g. JSON encoding middleware it can be a nested map
- if adapter supports it it can be a Stream with any of the above
:opts- custom, per-request middleware or adapter options
Examples
ExampleApi.request(method: :get, url: "/users/path")
# use shortcut methods
ExampleApi.get("/users/1")
ExampleApi.post(client, "/users", %{name: "Jon"})
@spec request!(Tesla.Env.client(), [option()]) :: Tesla.Env.t() | no_return()
Perform request and raise in case of error.
This is similar to request/2 behaviour from Tesla 0.x
See request/2 for list of available options.
@spec run(Tesla.Env.t(), Tesla.Env.stack()) :: Tesla.Env.result()
@spec trace(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.result()
Perform a TRACE request.
See request/1 or request/2 for options definition.
trace("/users")
trace("/users", query: [scope: "admin"])
trace(client, "/users")
trace(client, "/users", query: [scope: "admin"])
trace(client, "/users", body: %{name: "Jon"})
@spec trace!(Tesla.Env.client(), Tesla.Env.url(), [option()]) :: Tesla.Env.t() | no_return()
Perform a TRACE request.
See request!/1 or request!/2 for options definition.
trace!("/users")
trace!("/users", query: [scope: "admin"])
trace!(client, "/users")
trace!(client, "/users", query: [scope: "admin"])
trace!(client, "/users", body: %{name: "Jon"})
@spec update_assign(Tesla.Env.t(), atom(), any(), (any() -> any())) :: Tesla.Env.t()
Updates assign key in Tesla.Env with the given function or default.
If key is present in assigns then the existing value is passed to fun and its
result is used as the updated value of key. If key is not present in assigns,
default is inserted as the value of key. The default value will not be passed
through the update function.
See also update_assign!/3.
Examples
iex> env = %Tesla.Env{assigns: %{counter: 10}}
iex> env = Tesla.update_assign(env, :counter, 1, &(&1 + 1))
iex> env = Tesla.update_assign(env, :other, 1, &(&1 + 1))
iex> env.assigns
%{counter: 11, other: 1}
@spec update_assign!(Tesla.Env.t(), atom(), (any() -> any())) :: Tesla.Env.t()
Updates assign key in Tesla.Env with the given function.
Raises if the key is not set.
See also update_assign/4.
Examples
iex> env = %Tesla.Env{assigns: %{counter: 1}}
iex> env = Tesla.update_assign!(env, :counter, &(&1 + 1))
iex> env.assigns
%{counter: 2}