HTTPipe ISC License Documentation

HTTPipe is an adapter-driven HTTP library for Elixir that provides a way to build composable HTTP requests.

Inspired by the Plug library, HTTPipe provides a similar system by which an HTTPipe.Conn struct is built and dispatched; though unlike Plug it maintains the request and response under two separate keys.

HTTPipe does not actually handle the data-interchange, instead it relies on a adapter library specified by the user. The adapter must conform to the HTTPipe.Adapter behaviour. Specification of the adapter is done globally with the httpipe.adapter_module configuration value, but HTTPipe also allows adapters to be specified on a per-request basis. This can be helpful for testing scenarios when you need to use a mocked adapter for a test.

Configuring an Adapter

To start using HTTPipe with you’ll need an adapter. Adapters ship separate from HTTPipe, so you can choose the one that best suits you. The easiest one to start with is the Hackney Adapter. We can configure it in the mix.exs of a project like so:

def deps do
    {:httpipe_adapters_hackney, "~> 0.9"},
    {:httpipe, "~> 0.9}

Then call mix deps.get. Now in your config/config.exs file, set the Hackney Adapter as the default:

config :httpipe, :adapter, HTTPipe.Adapters.Hackney

First Request

HTTPipe provides some quick-start functions in the HTTPipe module that we can immediately test out. For example:

{:ok, conn} = HTTPipe.get("")

conn.response.status_code # 200

You can also experiment with looking at conn.response.body and conn.response.headers. This is simple stuff, though. Let’s get into what HTTPipe is really about.

Getting Composable

The composable suite of functions is kept in the HTTPipe.Conn module. We can make the same request from the previous section using the composable functions:

{:ok, conn} =
  |> HTTPipe.Conn.put_req_url("")
  |> HTTPipe.Conn.execute()

conn.response.status_code # 200

This is slightly more verbose, but the beauty of it comes in being able to break up the composition of the Conn:

def new_conn() do
  |> HTTPipe.Conn.put_req_header("Accept", "application/json")
  |> HTTPipe.Conn.put_req_header("Accept-Charset", "utf-8")
  |> HTTPipe.Conn.put_req_header("Connection", "keep-alive")
  |> HTTPipe.Conn.put_req_header("Content-Type", "application/json; charset=utf8")
  |> HTTPipe.Conn.put_req_header("X-Api-Key", "81b31106741cad9d9f6e")

def get_user(user_id) do
  {:ok, conn} =
    |> HTTPipe.Conn.put_req_url(@base_url <> "/users/#{user_id}")
    |> HTTPipe.Conn.put_req_param("include", "username,first_name,last_name")
    |> HTTPipe.Conn.put_req_method(:get)
    |> HTTPipe.Conn.execute()

For ease-of-use, you can of course alias HTTPipe.Conn, just be careful not to confuse it with Plug.Conn if you are using both in the same project.

Inspecting Your Connection

In an IEx console, try copying and pasting the following:

conn =
conn = HTTPipe.Conn.put_req_header(conn, "Accept", "application/json")
conn = HTTPipe.Conn.put_req_header(conn, "Accept-Charset", "utf-8")
conn = HTTPipe.Conn.put_req_header(conn, "Connection", "keep-alive")
conn = HTTPipe.Conn.put_req_header(conn, "Content-Type", "application/json; charset=utf8")
conn = HTTPipe.Conn.put_req_header(conn, "X-Api-Key", "81b31106741cad9d9f6e")
conn = HTTPipe.Conn.put_req_url(conn, "https://localhost/users/51")
conn = HTTPipe.Conn.put_req_param(conn, "include", "username,first_name,last_name")
conn = HTTPipe.Conn.put_req_method(conn, :get)

But what about...

There are plenty of existing HTTP libraries out there. Why another one? Part of the inspiration came out of a discussion on the Elixir Slack about the usage of HTTPoison versus using hackney directly. A few users mused that they would like an HTTP library that was composable in much the same way Ecto and Plug are.


HTTPoison is a fantastic library by Eduardo Gurgel that provides Elixir syntatic sugar for the Erlang hackney HTTP library. The two major features that HTTPipe provides over HTTPoison are better documentation and composable HTTP requests.


HTTPotion is a libary that provides Elixir syntatic sugar for the Erlang ibrowse HTTP library. (HTTPotion was the original; HTTPoison was created to provide a similar interface but for hackney). HTTPotion is definitely not an option for users who don’t like ibrowse, though. It also doesn’t have composable HTTP requests.


Tesla is a recent package that provides an adapter-driven HTTP library, but its attempts to use macros to build API wrappers doesn’t feel right in Elixir.


hackney is certainly one of the ranking Erlang packages. It’s well thought-out, has clear boundaries of responsibility, is well documented, and is easy to use. It doesn’t have composable HTTP requests, though. (Yes, there might be a theme to this list.)

Interoperability with HTTPoison & HTTPotion

HTTPipe is designed to be roughly interoperable with the basic functions from HTTPoison and HTTPotion. It provides the get/3, post/4, put/4, delete/3, head/3, patch/4, options/3, and request/5 (and their bang! style equivalents) to get you out the door. These will be converted to HTTPipe.Conn structs and executed immediately.

Unlike HTTPoison/HTTPotion, HTTPipe returns an HTTPipe.Conn struct which will not conform to any existing pattern matching you may do on Response structs from other libraries. Typically, you will have to rearrange your pattern matching to be on the internal :response key of the Conn struct.

Ongoing Improvements

For a list of improvements being considered, see the RFC issue list.

Copyright (c) 2016 David Antaramian

Licensed under the ISC License