Basic code to use mint (http client)

Hello,

I am trying to use mint to make some http requests with Elixir, and reading the docs I wrote the following code.

It works fine (for basic GET requests and everything is hardcoded, it’s normal, just a test) but it seems a bit to much to use a library.

Questions at the end of the post.

defmodule HTTP do
  @empty_state %{data: [], done: false}

  def run do
    with {:ok, conn} <- Mint.HTTP.connect(:http, "httpbin.org", 80),
         {:ok, conn, _ref} <- Mint.HTTP.request(conn, "GET", "/", [], nil) do
      handle_response(conn, @empty_state)
    end
  end

  defp handle_response(conn, state) do
    receive do
      message ->
        case Mint.HTTP.stream(conn, message) do
          {:ok, conn, responses} ->
            case Enum.reduce(responses, state, &handle_res/2) do
              # Loop ends here
              %{done: true} = state -> {:ok, state}
              %{done: false} = state -> handle_response(conn, state)
            end

          {:error, _, reason, _} ->
            {:error, reason}

          :unknown ->
            exit({:unexpected, message})
        end
    end
  end

  defp handle_res({:status, _, status}, state),
    do: Map.put(state, :status, status)

  defp handle_res({:headers, _, headers}, state),
    do: Map.put(state, :headers, headers)

  defp handle_res({:data, _, data}, state),
    do: Map.update!(state, :data, fn acc -> [data | acc] end)

  defp handle_res({:done, _}, state) do
    Map.update!(state, :data, fn acc ->
      acc
      |> :lists.reverse()
      |> Enum.join("")
    end)
    |> Map.put(:done, true)
  end
end

Task.async(fn -> HTTP.run() end)
|> Task.await()
|> case do
  {:ok, state} ->
    state
    |> Map.get(:data)
    |> IO.puts()

  other ->
    IO.inspect(other, pretty: true)
end


A quick note : I intend to use this from a GenServer, and I have no concerns about performance for this project, so to avoid handling messages, I will spawn a Task to handle the request, so I do not care about the request reference or :unknown messages. Also I know there are other responses possibles.

But again I do not expect other messages.

Questions

  • Is my code :ok ? I’ll take any remarks.
  • Am I expected to do that to use this library ?
  • Do you think mint should provide a helper like this for basic single requests ?
  • If I got it right, connect/3 is separated from request/5 for connection reuse. Can I do multiple requests with the same conn ? And if yes, should I use the conn from connect() or the last updated one ?

Thank you !

If you’re just looking to make some requests, look at HTTPoison (based on hackney) or Mojito (based on Mint).

Mint is a low level library which is pretty high effort if you’re not looking specifically for the features it offers. It explicitly doesn’t provide helpers to do requests, look at Mojito for that.

2 Likes

what @jola said - just wanted to add the tesla https://github.com/teamon/tesla library which is pretty nice for creating an abstraction/module for your different requests etc…

2 Likes

I used to use hackney but those libraries seem great too :slight_smile:

I highly recommend Tesla. It supports changing of the underlying HTTP client while providing a very sensible and convenient thin abstraction layer above them.

5 Likes