Packard_Goose
Curl command into Tesla post function
I have this command that works in terminal
curl "https://api.mysite.com/protected/json/new -d "user[email]=link@hotmail.com&user[cellphone]=112334558864&user[country_code]=49
I tried a few different ways with Tesla using the post function to replicate the request. Nothing I’m trying works but this is the latest attempt
post(client, “/new”, “user[email]= link@hotmail.com&user[cellphone]=112334558864&user[country_code]=49”)
Does anyone know of the translation into Tesla for essentially posting arrays with the post function?
Marked As Solved
7stud
You just need to add the Tesla.Middleware.FormUrlencoded plug to your pipeline, then specify a map for the body of the request:
request_body = %{
"user[email]" => "link@hotmail.com",
"user[cellphone]" => 12345,
"user[country_code]" => 49
}
So, something like this:
defmodule MyClient do
use Tesla
plug Tesla.Middleware.BaseUrl, "https://api.mysite.com"
plug Tesla.Middleware.FormUrlencoded
def go do
request_body = %{
"user[email]" => "link@hotmail.com",
"user[cellphone]" => 12345,
"user[country_code]" => 49
}
path = "/protected/json/new"
{:ok, response} = post(path, request_body)
end
end
On the server side, I see the post body:
user%5Bcellphone%5D=12345&user%5Bcountry_code%5D=49&user%5Bemail%5D=link%40hotmail.com
That is different than the post body that your curl command produces:
user[email]=link@hotmail.com&user[cellphone]=12345&user[country_code]=49
However, the post body produced by curl does not conform to the spec for the Content-Type application/x-www-form-urlencoded, which is what the -d flag automatically sets as the Content-Type header in the curl post request:
-d, --data <data>
(HTTP) Sends the specified data in a POST request to the
HTTP server, in the same way that a browser does when a
user has filled in an HTML form and presses the submit
button. This will cause curl to pass the data to the
server using the content-type application/x-www-form-urlencoded.
The spec (see 17.13.4 Form content types) requires that all non letter/number characters, i.e. all non alphanumeric characters, be escaped with % character codes:
application/x-www-form-urlencoded
…Forms submitted with this content type must be encoded as follows:
- …names and values are escaped. Space characters are replaced by
+, and then reserved characters are escaped as described in RFC1738, section 2.2: Non-alphanumeric characters are replaced by%HH, a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as “CR LF” pairs (i.e.,%0D%0A).- The control names/values are listed in the order they appear in the document. The name is separated from the value by
=and name/value pairs are separated from each other by&.
curl does allow you to specify that you want the post data to be percent encoded using the --data-urlencode flag instead of -d , but that still doesn’t produce the same post body as tesla. This is what I get:
user[email]=link%40hotmail.com%26user%5Bcellphone%5D%3D12345%26user%5Bcountry_code%5D%3D49
For some reason, curl does not escape the brackets everywhere as can be seen in user[email]. Confounding. Edit: Ah. To get curl to percent encode the leading name in the data, you have to prepend the data with an equals sign:
--data-urlencode '=user[email]=link@hotmail.com&user[cellphone]=12345&user[country_code]=49'
and the server receives the post body:
user%5Bemail%5D%3Dlink%40hotmail.com%26user%5Bcellphone%5D%3D12345%26user%5Bcountry_code%5D%3D49
Unfortunately, that still does not conform to the spec: curl replaces the equal signs and the ampersands with percent escapes, which confuses the server and the server can’t extract the key/value pairs. Compare to tesla:
user%5Bcellphone%5D=12345&user%5Bcountry_code%5D=49&user%5Bemail%5D=link%40hotmail.com
Tesla get’s it right and curl doesn’t.
Also Liked
BrightEyesDavid
I haven’t checked its behaviour with this data, but in case you wish to try a CLI HTTP client other than curl, I’ve had success with https://httpie.org . My issue with curl was body wrapping, and, if I remember correctly, HTTPie just did it right by default.







