HTTP requests with headers (api key) - getting error: init terminating in do_boot


main() ->
    API_KEY = "...",
    URL = "...",

    {ok, {{_, 200, _}, _, Body}} = httpc:request(get, {URL, ["Authorization"], API_KEY}, [], []),

I’m trying to send a http request to the URL, however, im unsure if the headers are correct with the api key …

I get the error:

{"init terminating in do_boot",{{badmatch,{error,invalid_request}},[{api,main,0,[{file,"api.erl"},{line,10}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ({{badmatch,{error,invalid_request}},[{api,main,0,[{_},{_}]},{init,start_em,1,[]},{init,do_boot,3,[]}]})

Crash dump is being written to: erl_crash.dump...done
1 Like

The second argument to httpc:request/4 has type httpc:request() which is documented here. It is a tuple with either two or four elements, not three as in your example.

{url(), headers()} | {url(), headers(), content_type(), body()}

Probably what you actually want is: {URL, [{"Authorization", API_KEY}]}.

** exception error: no function clause matching httpc:request(get,
                                                              {"url here",
                                                                 "api key here"}]}) (httpc.erl, line 157)
     in function  api:main/0 (api.erl, line 8)

why do I still get this?
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, {URL, [{"Authorization", API_KEY}]})

1 Like

Looks like you’re calling httpc:request/2 with the wrong kind of second argument. It expects url() and then profile() | pid() (i.e. an atom or a pid for arg 2), in which the second argument Profile is (I think) a way to specify a connection profile other than the default service profile created by inets:start/0. You’re giving it the HTTPOptions structure required by httpc:request/4, so function clause request/2 isn’t matching, hence the error.

It’s all specified in the httpc doc but the profile stuff is definitely a bit abstruse :grimacing: There are better examples on the HTTP Client page.

Basically though, if you’ve already got the inets app running then you don’t have to specify a profile, so you can just call httpc:request/4 like httpc:request(get, {URL, [{"Authorization", API_KEY}]}, [], []).

If you don’t already have inets service running, you can do this:

ok = ssl:start(), % necessary if your URL is https://...
ok = inets:start(),
Response = httpc:request(get, {URL, [{"Authorization", API_KEY}]}, [], []).

      {"date","Tue, 22 Nov 2022 18:04:41 GMT"},
      {"server","ECS (dcb/7EEC)"},
      {"content-type","text/html; charset=UTF-8"},
      {"expires","Tue, 29 Nov 2022 18:04:41 GMT"},
      {"last-modified","Thu, 17 Oct 2019 07:18:26 GMT"},
     "<!doctype html>\n<html>\n[...]</html>\n"}}

(You’ll maybe also get a cacertfile warning in there but that’s beyond this question.)

You might also want to have a look at hackney HTTP client library. It’s a bit friendlier than httpc, there’s a hackney:request/3 which just takes Method, URL, Headers which seems like what you want to do.

Good luck :four_leaf_clover:


thanks for the detailed reply … but somehow my request is also 403 ( invalid auth), so something must be wrong still … api key is correct tho and works in my elixir project just fine, just doesnt in erlng

1 Like

Oh, yeah, 403 Forbidden means it’s getting the Authorization header but the contents aren’t valid. You probably need to specify the authorization scheme. If it’s basic auth with a user:pass pair, then assuming API_KEY is a base64-encoded string, something like [{"Authorization", "Basic " ++ API_KEY}] should do the trick; if that isn’t what API_KEY is, then API_KEY=base64:encode_to_string("user:pass") will get you that. Or if it’s a ‘bearer’ token, you’ll need to specify that. (Or whichever auth it’s using.) This is part of HTTP though, not erlang or httpc in particular.