Erlang httpc appends :default

total_requests = 10
concurrency = 2

#url = "https://httpbin.org/anything"
method = :get

#payload = '{"some": "data"}'

:inets.start()
# :ssl.start()

average_time =
  1..total_requests
  |> Task.async_stream(
    fn _ ->
      start_time = System.monotonic_time()
      id = :rand.uniform(10_000) |> Integer.to_charlist()
      headers = [{'TransactionID', id}, {'SenderID', 'CON'}, {'Authorization', 'Basic token'}]
      url = 'endpoint'
      result = :httpc.request(method, {url, headers, 'application/json'}, [], [headers_as_is: true])
      IO.puts("#{inspect result}")

      System.monotonic_time() - start_time
    end,
    max_concurrency: concurrency
  )
  |> Enum.reduce(0, fn {:ok, req_time}, acc ->
    acc + req_time
  end)
  |> System.convert_time_unit(:native, :millisecond)
  |> Kernel./(total_requests)

The above elixir script returns the below error

** (FunctionClauseError) no function clause matching in :httpc.request/5
(inets 7.4.1) httpc.erl:149: :httpc.request(:get, {‘endpoint’, [{‘TransactionID’, ‘3742’}, {‘SenderID’, ‘CON’}, {‘Authorization’, ‘Basic Auth’}], [‘application/json’], ‘hi’}, [], [], :default)

I’m not quite sure how :default is being added to the function triggering the above error.

When you call :https.request/4 you are calling:

request(Method, Request, HttpOptions, Options) ->
    request(Method, Request, HttpOptions, Options, default_profile()). 

And as you can see its delegating to :https.request/5 with the default profile which, I strongly suspect, is :default. So thats not the the real issue.

Reading the code suggests that when the request is a :get then the request cannot have a body (your 'hi'). A guard clause is checking that if content type and body are provided then only :post, :patch, :put and :delete methods are allowed.

1 Like

Sorry, my mistake, the request body is empty but still throws that error. I’ve modified my original post.

Content type is also not permitted on :get request (your 'application/json'). Which makes sense since without a body there is no reason for a content type.

3 Likes

Thanks a bunch, after removing the content-type and adding a few additional headers, it’s working as expected. Once headers_as_is is set, there are a few additional headers that must be set otherwise the upstream server rejects the request - 400 Bad request.