How to POST params fields or JSON with curl

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the web-development category.

Last Updated: 2024-05-07

I was trying to send JSON commands to the Project M /commands POST endpoint but without much luck.

I realized I was lacking some understanding of HTTP POST, thus this piece.

Typical case of a web form without binary data

The values are sent in the request body, in the format that the content type specifies. The following shows an example. Note the necessary blank line between the HTTP header and the body (containing the params)

POST /path/script.cgi HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Usually the content type is application/x-www-form-urlencoded, so the request body uses the format you see above. On the command line with curl, this gets generated with the -d flag, e.g. curl -d home=Cosby -d favorite flavor=flies would generate a post chunk that looks like the above.

Case of a web form with binary data

When you use a file upload in the form, you use the multipart/form-data encoding instead, which has a different format.

Curl now requires you to use -F for each field (not just the data to be uploaded!)

curl -X POST -F person=anonymous -F secret=@file.txt http://example.com/submit.cgi

Note too the use of the @file.txt to indicate that a local file should be sent.

The generated HTTP is something like what follows

POST /submit.cgi HTTP/1.1
Host: example.com
User-Agent: curl/7.46.0
Accept: */*
Content-Length: 313
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------d74496d66958873e

--------------------------d74496d66958873e
Content-Disposition: form-data; name="person"

anonymous
--------------------------d74496d66958873e
Content-Disposition: form-data; name="secret"; filename="file.txt"
Content-Type: text/plain

contents of the file
--------------------------d74496d66958873e--

The Content-Type header has a boundary that consists of random digits and is used to separate data parts. Each part for a name=X area, where X is the parameter key name. Inside the following body, is either the parameter value (e.g. anonymous, for the person field) or the file contents.

JSON

How do we post JSON from command line?

curl -X POST -H 'Content-Type: application/json' -d '{"username":"davidwalsh","password":"something"}' http://domain.tld/login

We use -d again and just give it the FULL JSON load. -d alone would use Content-Type: application/x-www-form-urlencoded like a HTML form. But the Content-Type bit overrides it.

Note the necessary double quoting of the key names as well as values in the JSON;

POST / HTTP/1.1
Host: example.com
User-Agent: curl/7.64.1
Accept: */*
Content-Type: application/json
Content-Length: 48

* upload completely sent off: 48 out of 48 bytes

Postman tool

Aside from all this, it's probably easiest to construct a correct curl request using the Postman tool.

Resources