mikejm

mikejm

Can't get basic HTTPoison.post working? "1st argument: not an iodata term"

I am attempting to make my first Phoenix HTTP request using HTTPoison but it is not working and I cannot figure out why.

If I create a basic project with HTTPoison in it, then go to iex on this project, I type in the following commands:

userPass = "user:pass"
base64UserPass = Base.encode64(userPass)
authString = "Basic " <> base64UserPass
headers = ["Authorization": authString, "Content-Type": "application/json"] 
headers = [{"Authorization", authString}, {"Content-Type", "application/json"}] 
body = [language: "sql", command: "select from Profile"]
body = [{"language", "sql"}, {"command", "select from Profile"}]
url = "http://serveraddress.amazonaws.com:2480/api/v1/command/mydb"
HTTPoison.post(url, body, headers)

I am not sure which syntax I should be using for the headers or body out of those options, but either way it doesn’t even seem to get that far as I get:

** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not an iodata term

    :erlang.iolist_to_binary([{"language", "sql"}, {"command", "select from Profile"}])
    (hackney 1.20.1) /deps/hackney/src/hackney_request.erl:352: :hackney_request.handle_body/4
    (hackney 1.20.1) /hackney/src/hackney_request.erl:87: :hackney_request.perform/2
    (hackney 1.20.1) /deps/hackney/src/hackney.erl:378: :hackney.send_request/2
    (httpoison 2.2.1) lib/httpoison/base.ex:888: HTTPoison.Base.request/6
    iex:22: (file)

I have searched for info on what I’m doing wrong.

I found this thread that says I should use \ to escape the quotes or use Jason.encode somehow to circumvent this issue, but I could not figure out how to do this:
https://elixirforum.com/t/1st-argument-not-an-iodata-term-error-for-multilingual-text/48225

I found this but that suggested I am not doing anything entirely wrong I can see:
https://stackoverflow.com/questions/59224740/httpoison-doesnt-accept-this-custom-header

I tried:

body = Jason.encode(%{"language": "sql", "command": "select from Profile"})
headers = Jason.encode(%{"Authorization": authString, "Content-Type": "application/json"}) 

But that didn’t work either as it said it was bad data. So I don’t actually know what the problem is or how to fix it. The request is not being rejected by the server, but rather it is just giving Elixir errors without sending as I can’t find the right syntax.

Any help? Thanks.

Marked As Solved

mikejm

mikejm

Thank you for your advice. Between that and this example I found:

https://stackoverflow.com/questions/37385314/httpoison-insert-body-parameters-in-elixir

I was able to figure it out. The correct approach is:

userPass = "user:pass"
base64UserPass = Base.encode64(userPass)
authString = "Basic " <> base64UserPass
url = "http://serveraddress.amazonaws.com:2480/api/v1/command/mydb"
headers = ["Authorization": authString, "Content-Type": "application/json"] 
headers = [{"Authorization", authString}, {"Content-Type", "application/json"}] 
body = Jason.encode!(%{language: "sql", command: "select from Profile"})
HTTPoison.post(url, body, headers)

So I just needed to “encode” the body and the headers was supposed to be used in either format above. Worked and returned correct from server. Thanks again.

Perhaps this will be helpful to other people, but I find of all programming languages I’ve gone into, Elixir/Pheonix has the most opaque documentation. Most of the Hex Docs (like HTTPoison) have no examples of any use that would show things work.

I’m not sure why that is. I suspect there are very few “beginners” or “intermediate” programmers using Elixir in any scenario so everything is written with the notion you already know what you’re supposed to do intuitively.

Also Liked

D4no0

D4no0

First of all the body parameter should be a string, not a list.

Second thing is that Jason.encode/2 returns response in format {:ok, binary}, you either pattern match on response or use the bang variant Jason.econde!/2.

The third thing is that jason doesn’t know how to encode tuples, since json format doesn’t have this concept, so you have to use a map instead:

body = %{language: "sql", command: "select from Profile"}
body_binary = Jason.encode!(body)
D4no0

D4no0

This is absolutely not true. Elixir from conception was created to have a good documentation infrastructure in mind and all mature libraries have great documentation. It is a lot to take in as a beginner as @benwilson512 said, because there are a lot of things to unpack.

A short description on how you should read documentation is the following:

  1. Open the function documentation on hexdocs for HTTPoison.post/4
  2. Look at the specs of the function, in our case we have the following:
post(url, body, headers \\ [], options \\ [])

# spec
post(binary(), any(), headers(), Keyword.t()) ::
{:ok,
 HTTPoison.Response.t()
 | HTTPoison.AsyncResponse.t()
 | HTTPoison.MaybeRedirect.t()}
| {:error, HTTPoison.Error.t()}
  1. For headers, if you follow the link you will get the following spec:
headers() ::
  [{atom(), binary()}]
  | [{binary(), binary()}]
  | %{required(binary()) => binary()}
  | any()

This states clearly that you can create headers in the following formats:

["Authorization": authString, "Content-Type": "application/json"] 
[{"Authorization", authString}, {"Content-Type" "application/json"}]
%{"Authorization" => authString, "Content-Type" => "application/json"}  
  1. Now the body parameter is set as any, however if you follow the description of the parameter from the function, you will be redirected to request/5 and then to HTTPoison.Request where there is a clear description of the format:

:body:
binary, char list or an iolist
{:form, [{K, V}, …]} - send a form url encoded
{:file, “/path/to/file”} - send a file
{:stream, enumerable} - lazily send a stream of binaries/charlists

Could this documentation be improved? definetly, more examples could be added also, nothing is perfect
Is it missing vital documentation? absolutely no

And that is all you need to know, as long as you respect these specs, you requests should work as expected.

My advice is that if you don’t want to keep shooting yourself in the leg, take some time to learn elixir syntax, preferably read a book that covers the philosophy of the language, then dive into more complex things like phoenix, as that is a full fledged mature framework that is not meant to be beginner friendly, but to get things done.

arcyfelix

arcyfelix

One very important thing - Elixir uses snake case naming. If you don’t follow that, formatting might have issues.

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
nobody
Hi! In PHP: $SERVER['SERVERADDR'] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I'm a nov...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

Other popular topics Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I'm a nov...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement