Monthly Downloads: 25,156
Programming language: Elixir
License: The Unlicense
Tags: HTTP     Client    
Latest version: v3.1.2

httpotion alternatives and similar packages

Based on the "HTTP Client" category.
Alternatively, view httpotion alternatives based on common mentions on social networks and blogs.

Do you think we are missing an alternative of httpotion or a related project?

Add another 'HTTP Client' Package


hex.pm version hex.pm downloads API Docs unlicense


HTTP client for Elixir, based on ibrowse. Continues the HTTPun tradition of HTTParty, HTTPretty, HTTParrot and HTTPie.

Note: unfortunately, ibrowse seems a bit buggy and not super actively maintained. You might want to check out Tesla with hackney instead, and this cert verification setup.


Add HTTPotion to your project's dependencies in mix.exs:

  defp deps do
      {:httpotion, "~> 3.1.0"}

  def application do
    [ applications: [:httpotion] ]
    # Application dependency auto-starts it, otherwise: HTTPotion.start

And fetch your project's dependencies:

$ mix deps.get


Note: You can load HTTPotion into the Elixir REPL by executing this command from the root of your project:

$ iex -S mix

Note: HTTPotion now enables certificate verification by default, using a few default CA bundle paths (/etc/ssl/cert.pem etc.) or the certifi package (which is not a mandatory dependency).

Some basic examples:

iex> response = HTTPotion.get "https://httpbin.org/get"
  body: "{\n…",
  headers: %HTTPotion.Headers{ hdrs: %{"connection" => "keep-alive", …} },
  status_code: 200

iex> HTTPotion.Response.success?(response)

# Response headers are wrapped to allow case-insensitive access (and to support both atoms and strings)
iex> response.headers[:sErvEr]

iex> response.headers["ConTenT-TyPe"]

# Response headers can have multiple values
iex> response = HTTPotion.get "https://httpbin.org/response-headers?foo=1&foo=2&bar=1"
  body: "{\n…",
  headers: %HTTPotion.Headers{ hdrs: %{"foo" => ["1", "2"], "bar" => "1" …} },
  status_code: 200

# You can provide a map for the query string
iex> HTTPotion.get("https://httpbin.org/get", query: %{page: 2})
%HTTPotion.Response{body: "…", headers: …, status_code: 200}

# Follow redirects
iex> HTTPotion.get("https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F", follow_redirects: true)
%HTTPotion.Response{body: "…<title>Example Domain</title>…", headers: …, status_code: 200}

# Send form data
iex> HTTPotion.post "https://httpbin.org/post", [body: "hello=" <> URI.encode_www_form("w o r l d !!"),
  headers: ["User-Agent": "My App", "Content-Type": "application/x-www-form-urlencoded"]]
%HTTPotion.Response{body: "…", headers: …, status_code: 200}

# Use a custom method
iex> HTTPotion.request :propfind, "http://httpbin.org/post", [body: "I have no idea what I'm doing"]
%HTTPotion.Response{body: "…", headers: …, status_code: 405}

# Send Basic auth credentials
iex> HTTPotion.get "https://httpbin.org/basic-auth/foo/bar", [basic_auth: {"foo", "bar"}]
  body: "…",
  headers: %HTTPotion.Headers { hdrs: %{"Access-Control-Allow-Credentials": "true", …} },
  status_code: 200

# Pass options to ibrowse (note that it usually takes char_lists, not elixir strings)
iex> HTTPotion.get "https://check-tls.akamaized.net", [ ibrowse: [ ssl_options: [ versions, [:'tlsv1.1'] ] ] ]
%HTTPotion.Response{body: "…TLS SNI: present - Check TLS - (https,tls1.1,ipv4)…", headers: …, status_code: 200}

# Change the timeout (default is 5000 ms)
iex> HTTPotion.get "https://example.com", [timeout: 10_000]

# If there is an error a `HTTPotion.ErrorResponse` is returned
iex> HTTPotion.get "http://localhost:1"
%HTTPotion.ErrorResponse{message: "econnrefused"}

# You can also raise `HTTPError` with the `bang` version of request
iex> HTTPotion.get! "http://localhost:1"
** (HTTPotion.HTTPError) econnrefused

The Response is a struct, you can access its fields like: response.body.

response.headers is a struct (HTTPotion.Headers) that wraps a map to provide case-insensitive access (so you can use response.headers[:authorization] and it doesn't matter if the server returned AuThOrIZatIOn or something).

HTTPError is an exception that happens when a bang request (request! / get! / …) fails.

Available options and their default values:

  body: "",                # Request's body contents, e.g. "{json: \"string\"}"
  headers: [],             # Request's headers, e.g. [Accept: "application/json"]
  query: nil,              # Query string, e.g. %{page: 1}
  timeout: 5000,           # Timeout in milliseconds, e.g. 5000
  basic_auth: nil,         # Basic auth credentials, e.g. {"username", "password"}
  stream_to: nil,          # A process to stream the response to when performing async requests
  direct: nil,             # An ibrowse worker for direct mode
  ibrowse: [],             # ibrowse options
  auto_sni: true,          # Whether TLS SNI should be automatically configured (does URI parsing)
  follow_redirects: false, # Whether redirects should be followed

Metaprogramming magic

You can extend HTTPotion.Base to make cool HTTP API wrappers (this example uses Poison for JSON):

defmodule GitHub do
  use HTTPotion.Base

  def process_url(url) do
    "https://api.github.com/" <> url

  def process_request_headers(headers) do
    Dict.put headers, :"User-Agent", "github-potion"

  def process_response_body(body) do
    body |> Poison.decode!
iex> GitHub.get("users/unrelentingtech").body["public_repos"]

Read the source to see all the hooks.

Keep in mind that process_response_body and process_response_chunk get iodata. By default, they call IO.iodata_to_binary. But efficient parsers like Poison can work directly on iodata.

Asynchronous requests

You can get the response streamed to your current process asynchronously:

iex> HTTPotion.get "http://httpbin.org/get", [stream_to: self]
%HTTPotion.AsyncResponse{id: -576460752303419903}

iex> flush
  id: -576460752303419903,
  status_code: 200,
  headers: %HTTPotion.Headers{ hdrs: %{"connection" => "keep-alive", …} }
  id: -576460752303419903,
  chunk: "{\n…"
  id: -576460752303419903

Note that instead of process_response_body, process_response_chunk is called on the chunks before sending them out to the receiver (the stream_to process).

Direct access to ibrowse workers

ibrowse allows you to use its separate worker processes directly. We expose this functionality through the direct option.

Don't forget that you have to pass the URL to the worker process, which means the worker only communicates with one server (domain!)

iex> {:ok, worker_pid} = HTTPotion.spawn_worker_process("http://httpbin.org")

iex> HTTPotion.get "httpbin.org/get", [direct: worker_pid]
%HTTPotion.Response{body: "…", headers: ["Connection": "close", …], status_code: 200}

You can even combine it with async!

iex> {:ok, worker_pid} = HTTPotion.spawn_worker_process("http://httpbin.org")

iex> HTTPotion.post "httpbin.org/post", [direct: worker_pid, stream_to: self, headers: ["User-Agent": "hello it's me"]]
%HTTPotion.AsyncResponse{id: {1372,8757,656584}}

Type analysis

HTTPotion contains typespecs so your usage can be checked with dialyzer, probably via dialyxir or elixir-ls.

HTTPotion's tests are checked with dialyxir.


Please feel free to submit pull requests!

By participating in this project you agree to follow the Contributor Code of Conduct.


This is free and unencumbered software released into the public domain.
For more information, please refer to the UNLICENSE file or unlicense.org.

*Note that all licence references and agreements mentioned in the httpotion README section above are relevant to that project's source code only.