Packages
tesla
0.1.4
1.20.0
1.18.3
1.18.2
1.18.1
1.18.0
1.17.0
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.3
1.12.2
1.12.1
1.12.0
1.11.2
1.11.1
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
retired
1.8.0
1.7.0
1.6.1
1.6.0
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.0
1.0.0-beta.1
0.10.0
0.9.0
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.2
0.2.1
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
HTTP client library, with support for middleware and multiple adapters.
Current section
Files
Jump to
Current section
Files
lib/tesla.ex
defmodule Tesla.Env do
defstruct url: "",
method: nil,
status: nil,
headers: %{},
body: nil,
opts: []
end
defmodule Tesla.Builder do
@http_methods [:get, :head, :delete, :trace, :options, :post, :put, :patch]
defmacro __using__(_what) do
method_defs = for method <- [:get, :head, :delete, :trace, :options] do
quote do
# 4 args
def unquote(method)(fun, url, query, opts) when is_function(fun) and is_map(query) do
request(fun, unquote(method), url, query, nil, opts)
end
# 3 args
def unquote(method)(fun, url, query) when is_function(fun) and is_map(query) do
request(fun, unquote(method), url, query, nil, [])
end
def unquote(method)(fun, url, opts) when is_function(fun) do
request(fun, unquote(method), url, nil, nil, opts)
end
def unquote(method)(url, query, opts) when is_map(query) and is_map(query) do
request(unquote(method), url, query, nil, opts)
end
# 2 args
def unquote(method)(fun, url) when is_function(fun) do
request(fun, unquote(method), url, nil, nil, [])
end
def unquote(method)(url, query) when is_map(query) do
request(unquote(method), url, query, nil, [])
end
def unquote(method)(url, opts) do
request(unquote(method), url, nil, nil, opts)
end
# 1 args
def unquote(method)(url) do
request(unquote(method), url, nil, nil, [])
end
end
end
method_defs_with_body = for method <- [:post, :put, :patch] do
quote do
# 5 args
def unquote(method)(fun, url, query, body, opts) when is_function(fun) and is_map(query) do
request(fun, unquote(method), url, query, body, opts)
end
# 4 args
def unquote(method)(fun, url, query, body) when is_function(fun) and is_map(query) do
request(fun, unquote(method), url, query, body, [])
end
def unquote(method)(fun, url, body, opts) when is_function(fun) do
request(fun, unquote(method), url, nil, body, opts)
end
def unquote(method)(url, query, body, opts) when is_map(query) do
request(unquote(method), url, query, body, opts)
end
# 3 args
def unquote(method)(fun, url, body) when is_function(fun) do
request(fun, unquote(method), url, nil, body, [])
end
def unquote(method)(url, query, body) when is_map(query) do
request(unquote(method), url, query, body, [])
end
def unquote(method)(url, body, opts) do
request(unquote(method), url, nil, body, opts)
end
# 2 args
def unquote(method)(url, body) do
request(unquote(method), url, nil, body, [])
end
end
end
quote do
unquote(method_defs)
unquote(method_defs_with_body)
defp request(fun, method, url, query, body, opts) when is_function(fun) do
env = %Tesla.Env{
method: method,
url: Tesla.Builder.append_query_string(url, query),
body: body,
opts: opts
}
fun.(env, &call_middleware/1)
end
defp request(method, url, query, body, opts) do
request(fn (env, run) -> run.(env) end, method, url, query, body, opts)
end
import Tesla.Builder
Module.register_attribute(__MODULE__, :middleware, accumulate: true)
@before_compile Tesla.Builder
end
end
defmacro __before_compile__(env) do
middleware = Module.get_attribute(env.module, :middleware)
reduced = Enum.reduce(middleware, (quote do: call_adapter(env)), fn {mid, args}, acc ->
args = Macro.escape(args)
quote do
unquote(mid).call(env, fn(env) -> unquote(acc) end, unquote(args))
end
end)
quote do
def call_middleware(env) do
unquote(reduced)
end
end
end
def process_adapter_response(env, res) do
case res do
{status, headers, body} ->
%{env | status: status, headers: headers, body: body}
e -> e
end
end
def append_query_string(url, query) do
if query do
query_string = URI.encode_query(query)
if url |> String.contains?("?") do
url <> "&" <> query_string
else
url <> "?" <> query_string
end
else
url
end
end
defmacro adapter({:fn, _, _} = ad) do # pattern match for function
quote do
def call_adapter(env) do
Tesla.Builder.process_adapter_response(env, unquote(ad).(env))
end
end
end
defmacro adapter(adapter) do
quote do
def call_adapter(env) do
Tesla.Builder.process_adapter_response(env, unquote(adapter).call(env))
end
end
end
defmacro with(middleware, opts \\ []) do
quote do
@middleware {unquote(middleware), unquote(opts)}
end
end
defmacro defwrap(head, do: body) do
fun_var = Macro.var(:client_fun, __MODULE__)
head_with_client = case head do
{:when, ctx1, [{name, ctx2, args} | tl]} -> {:when, ctx1, [{name, ctx2, [fun_var | args]} | tl]}
{name, ctx, args} -> {:when, ctx, [{name, ctx, [fun_var | args]}, {:is_function, ctx, [fun_var]}]}
end
body_with_client = Macro.prewalk body, fn (ast) ->
case ast do
{fun, ctx, args} when fun in @http_methods -> {fun, ctx, [fun_var | args]}
other -> other
end
end
def_with_client = quote do
def unquote(head_with_client) do
unquote(body_with_client)
end
end
normal = quote do
def unquote(head) do
unquote(body)
end
end
[def_with_client, normal]
end
end
defmodule Tesla do
use Tesla.Builder
adapter Tesla.Adapter.Ibrowse
def build_client(stack) do
fn (env, run) ->
f = Enum.reduce(stack, run, fn ({mid, args}, acc) ->
fn (env) -> mid.call(env, fn(e) -> acc.(e) end, args) end
end)
f.(env)
end
end
def start do
Tesla.Adapter.Ibrowse.start
end
end