263

I can successfully create a place via curl executing the following command:

$ curl -vX POST https://server/api/v1/places.json -d "
  auth_token=B8dsbz4HExMskqUa6Qhn& \
  place[name]=Fuelstation Central& \
  place[city]=Grossbeeren& \
  place[address]=Buschweg 1& \
  place[latitude]=52.3601& \
  place[longitude]=13.3332& \
  place[washing]=true& \
  place[founded_at_year]=2000& \
  place[products][]=diesel& \
  place[products][]=benzin \
"

The server returns HTTP/1.1 201 Created.
Now I want to store the payload in a JSON file which looks like this:

// testplace.json
{
  "auth_token" : "B8dsbz4HExMskqUa6Qhn",
  "name" : "Fuelstation Central",
  "city" : "Grossbeeren",
  "address" : "Buschweg 1",
  "latitude" : 52.3601,
  "longitude" : 13.3332,
  "washing" : true,
  "founded_at_year" : 2000,
  "products" : ["diesel","benzin"]
}

So I modify the command to be executed like this:

$ curl -vX POST http://server/api/v1/places.json -d @testplace.json

This fails returning HTTP/1.1 401 Unauthorized. Why?

whirlwin
  • 16,044
  • 17
  • 67
  • 98
JJD
  • 50,076
  • 60
  • 203
  • 339
  • 1
    Also keep in mind that if you're uploading binary files, you should use `--data-binary`. – ahmet alp balkan Aug 07 '19 at 00:18
  • 2
    For anyone referencing this question for an answer to 'how do I specify the file that contains the JSON', note that it's with the `@` sign as given in the question e.g. `$ curl -vX POST http://server/api/v1/places.json -d @testplace.json`. This assumes that you are running curl from the directory that contains testplace.json - otherwise use e.g `@/some/directory/some.json` – Chris Halcrow Jun 01 '21 at 06:07

3 Answers3

441

curl sends POST requests with the default content type of application/x-www-form-urlencoded. If you want to send a JSON request, you will have to specify the correct content type header:

$ curl -vX POST http://server/api/v1/places.json -d @testplace.json \
--header "Content-Type: application/json"

But that will only work if the server accepts json input. The .json at the end of the url may only indicate that the output is json, it doesn't necessarily mean that it also will handle json input. The API documentation should give you a hint on whether it does or not.

The reason you get a 401 and not some other error is probably because the server can't extract the auth_token from your request.

Yves M.
  • 29,855
  • 23
  • 108
  • 144
mata
  • 67,110
  • 10
  • 163
  • 162
  • 11
    I was trying to use `cat file.json` after the `-d` and was having trouble with it, until I learned from this answer that I can use `@file.json`. Thanks :) – Shadi Jan 26 '17 at 06:16
  • 1
    note that if you need multiple headers you need to specify `-H`/`--header` multiple times, at least when tested in bash on Ubuntu. – Chaim Eliyah Sep 14 '17 at 01:24
8

To clarify how to actually specify a file that contains the JSON to post, note that it's with the @ sign as shown in the OP

e.g. a typical post to a local .NET Core API:

curl -X POST https://localhost:5001/api -H "Content-Type: application/json" -d @/some/directory/some.json

Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
2

You can cat the contents of a json file to curl via the --data-raw parameter

curl https://api.com/route -H 'Content-Type: application/json' --data-raw "$(cat ~/.json/payload-2022-03-03.json | grep -v '^\s*//')"

curl https://api.com/route -H 'Content-Type: application/json' -d @<(jq . ~/.json/payload-2022-03-03.json)

curl https://api.com/route -H 'Content-Type: application/json' -d @<(jq '{"payload": .}' < ~/.json/payload-2022-03-03.json)

Note: comments in the json file are filtered out via grep -v '^\s*//'

You can also pass the data to curl via stdin using grep or cat or jq

grep -v '^\s*//' ~/.json/payload-2022-03-03.json | curl https://api.com/route -H 'Content-Type: application/json' -d @-

cat ~/.json/payload-2022-03-03.json | grep -v '^\s*//' | curl https://api.com/route -H 'Content-Type: application/json' -d @-

jq . ~/.json/payload-2022-03-03.json | curl https://api.com/route -H 'Content-Type: application/json' -d @-

jq '{"payload": .}' < ~/.json/payload-2022-03-03.json | curl https://api.com/route -H 'Content-Type: application/json' -d @-

Andrew
  • 3,733
  • 1
  • 35
  • 36