How do you send json data with curl?

I have an http endpoint defined like this:

@anvil.server.http_endpoint('/test')
def test(what=None, who=None):

Why does this work as expected, that is the function arguments are correctly populated:

requests.post('https://app_api_url/test',data={"who":"me","what":"this"})

And these both don’t, that is the function arguments are not populated and data is a string in anvil.server.request.body.get_bytes():

curl -d '{"who":"me","what":"this"}' 'https://app_api_url/test'
curl -H 'Content-Type: application/json' -d '{"who":"me","what":"this"}' 'https://app_api_url/test'

I was expecting for the Python requests line and the sh curl with header line to do the same job.

I’ll like to point it out that url here is wrong. It should be

requests.post('https://app_api_url/_/api/test',data={"who":"me","what":"this"})

For example


requests.post('https://myapi.anvil.app/_/api/test',data={"who":"me","what":"this"})

In my question I shortened the url.

I made up a word intended to represent whatever needs to be there, because whatever is in the url does not affect the question.

My problem is not that the http endpoints don’t work. They do, which means I’m using the correct url. The question here is about curl… I think.

1 Like

you can try this

curl 'https://you_api_link' \
-H 'Content-Type: application/json' \
--data-binary '{"who":"me","email":"my_email@gmail.com"}'

I’ve not tested this but, from memory, I think anvil endpoints default to POST if you’re sending data and you need to tell curl to use that method (IIRC, that’s curl -X POST ...)

I have tried data-binary and makes no difference.

I think that if you provide -d ... it implicitly switches to post, but I have tried also explicitly using -X POST and makes no difference

Yep, you’re right!

How about using the -F option rather than -d?

curl -X POST -F 'who=me' -F 'what=this' https://app_api_url/test

If you’re not tied to curl, there’s always httpie

or try postman as well

Using -F sends this, I guess that’s what RFC 2388 likes, but it is not what Anvil likes:

--------------------------91fd2c69ff2f3bac
Content-Disposition: form-data; name="who"

me
--------------------------91fd2c69ff2f3bac
Content-Disposition: form-data; name="what"

this
--------------------------91fd2c69ff2f3bac--

I didn’t know httpie, it looks cool, but I was looking for something that works on Windows machines out of the box. They don’t even have Python.

I would like a unique way to send a request from any scripting language that runs inside other CAD, CAM or other proprietary applications. They all can create a text file and execute it with cmd /c, but some of them don’t know how to send http requests.

Oh well… I have control on the http endpoint, so I will parse the body. This is what I usually do, but in this case I thought I didn’t need to do it because the function was working, because I was only calling it with requests. Then one day I tried to use it with curl and it didn’t work.

This might work

Anvil populates the function arguments from urlencoded parameters (just like a query string), not from json.

This:

curl 'https://app_api_url/test' --data-urlencode 'who=me' --data-urlencode 'what=this'

Sends this in the body:

who=me&what=this

Unlike a query string appended to the URL in a GET, this request is a POST and the query string is sent in the body, so there is no 2000-ish character limit on the length. For example it is possible to send a text file with this:

curl 'https://app_api_url/test' --data-urlencode "file1=`cat file1`" --data-urlencode "file2=`cat file2`"

I haven’t used Unix in 30 years, I didn’t remember how to do it, but my fingers did and were able to type this command by themselves! And it worked! Magic fingers!
Still… please let me know if this is not the right way.

How about trying this, I got issue with google post before and it fixes:

curl 'https://app_api_url/test?who=me&what=this'

This has two problems: it is not POST (it would need -X POST) and it’s limited to 2000-ish characters (no solution for this)