Tesla

Tesla is an HTTP client losely based on Faraday. It embraces the concept of middleware when processing the request/response cycle.

WARNING: Tesla is currently under heavy development, so please don't use it in your production application just yet.

Nevertheless all comments/issues/suggestions are more than welcome - please submit them using GitHub issues, thanks!

Basic usage

# Start underlying ibrowse default adapter
Tesla.start
# Example get request
response = Tesla.get("http://httpbin.org/ip")
response.status # => 200
response.body # => '{\n "origin": "87.205.72.203"\n}\n'
response.headers # => %{'Content-Type' => 'application/json' ...}
# Example post request
response = Tesla.post("http://httpbin.org/post", "data")

Installation

Add tesla as dependency in mix.exs

defp deps do
[{:tesla, "~> 0.1.0"},
{:ibrowse, github: "cmullaparthi/ibrowse", tag: "v4.1.1"}, # default adapter
{:exjsx, "~> 3.1.0"}] # for JSON middleware
end

Creating API clients

Use Tesla.Builder module to create API wrappers.

For example

defmodule GitHub do
use Tesla.Builder
with Tesla.Middleware.BaseUrl, "https://api.github.com"
with Tesla.Middleware.Headers, %{'Authorization' => 'xyz'}
with Tesla.Middleware.EncodeJson
with Tesla.Middleware.DecodeJson
adapter Tesla.Adapter.Ibrowse
def user_repos(login) do
get("/user/" <> login <> "/repos")
end
end

Then use it like this:

GitHub.get("/user/teamon/repos")
GitHub.user_repos("teamon")

Adapters

Tesla has support for different adapters that do the actual HTTP request processing.

ibrowse

Tesla has built-in support for ibrowse Erlang HTTP client.

To use it simply include adapter Tesla.Adapter.Ibrowse line in your API client definition.

NOTE: Remember to start ibrowse first with Tesla.Adapter.Ibrowse.start before executing any requests.

ibrowse is also the default adapter when using generic Tesla.get(...) etc. methods.

Test / Mock

When testing it might be useful to use simple function as adapter:

defmodule MyApi do
use Tesla
adapter fn (env) ->
case env.url do
"/" -> {200, %{}, "home"}
"/about" -> {200, %{}, "about us"}
end
end
end

Middleware

Basic

JSON

NOTE: requires exjsx as dependency

If you are using different json library writing middleware should be straightforward. See json.ex for implementation.

Dynamic middleware

All methods can take a middleware function as the first parameter. This allow to use convinient syntax for modyfiyng the behaviour in runtime.

Consider the following case: GitHub API can be accessed using OAuth token authorization.

We can't use with Tesla.Middleware.Headers, %{'Authorization' => 'token here'} since this would be compiled only once and there is no way to insert dynamic user token.

Instead, we can use Tesla.build_client to create a dynamic middleware function:

defmodule GitHub do
# same as above
def client(token) do
Tesla.build_client [
{Tesla.Middleware.Headers, %{'Authorization' => "token: " <> token }}
]
end
end

and then:

client = GitHub.client(user_token)
client |> GitHub.user_repos("teamon")
client |> GitHub.get("/me")

Asynchronous requests

If adapter supports it, you can make asynchronous requests by passing respond_to: pid option:

Tesla.get("http://example.org", respond_to: self)
receive do
{:tesla_response, res} -> res.status # => 200
end