152

Consider the curl command below, is it possible to allow newline in JSON (without the minify) and execute directly in bash (Mac/Ubuntu)

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d \
'
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'

When I run the command above, seems error occurred at the second { How to fix the above command?

Updated: actually I was able to run the command without issue previously, not sure why problem happen recently.

Ryan
  • 10,041
  • 27
  • 91
  • 156
  • 2
    Can you tell us more about the error? Your example works "as is" on my system. `mymac > bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15) Copyright (C) 2007 Free Software Foundation, Inc.` – Eric Bolinger Jan 27 '16 at 21:00
  • Yup, works for me as well: `GNU bash, version 4.3.42(1)-release` – miken32 Jan 29 '16 at 04:43
  • 3
    Also check out [ANSI C-like string syntax](http://wiki.bash-hackers.org/syntax/quoting): `echo $'here is a newline:\nand here is a tab:\t'` – miken32 Jan 29 '16 at 19:50
  • 1
    `application/json` is the correct media type for JSON data -- see [RFC4627](https://www.ietf.org/rfc/rfc4627.txt) – Pocketsand Jan 10 '19 at 19:02

6 Answers6

211

I remembered another way to do this with a "Here Document" as described in the Bash man page and detailed here. The @- means to read the body from STDIN, while << EOF means to pipe the script content until "EOF" as STDIN to curl. This layout may be easier to read than using separate files or the "echo a variable" approach.

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: application/json; charset=utf-8' \
--data-binary @- << EOF
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}
EOF

NOTE: Use the --trace <outfile> curl option to record exactly what goes over the wire. For some reason, this Here Document approach strips newlines. (Update: Newlines were stripped by curl -d option. Corrected!)

Eric Bolinger
  • 2,722
  • 1
  • 13
  • 22
58

Along the lines of Martin's suggestion of putting the JSON in a variable, you could also put the JSON in a separate file, and then supply the filename to -d using curl's @ syntax:

curl -0 -v -X POST http://www.example.com/api/users \
  -H "Expect:" \
  -H 'Content-Type: text/json; charset=utf-8' \
  -d @myfile.json

The disadvantage is obvious (2 or more files where you used to have one.) But on the plus side, your script could accept a filename or directory argument and you'd never need to edit it, just run it on different JSON files. Whether that's useful depends on what you are trying to accomplish.

Bampfer
  • 2,120
  • 16
  • 25
33

For some reason, this Here Document approach strips newlines

@eric-bolinger the reason the Heredoc strips newlines is because you need to tell your Heredoc to preserve newlines by quoting the EOF:

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d @- <<'EOF'

{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}
EOF

Notice the single-ticks surrounding EOF the first time it's defined, but not the second.

Tim Gebhardt
  • 405
  • 5
  • 9
30

You should use outer double quotes, and the escape all inner quotes like this:

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d \
"
{
    \"field1\": \"test\",
    \"field2\": {
        \"foo\": \"bar\"
    }
}"
Dmitriy Korobkov
  • 867
  • 1
  • 11
  • 25
28

You could assign your json to a var:

json='
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'

Now you can forward this to curl using stdin:

echo $json | curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
-d @-
Martin Konecny
  • 57,827
  • 19
  • 139
  • 159
  • 1
    Using single quotes to surround the block means that you *cannot* use variables (e.g. `${username}`) in the JSON. – Air Jan 06 '17 at 03:10
  • 1
    Yup, but using double quotes means you can't use $ signs in your data. Pick which one is right for you. – Martin Konecny Jan 06 '17 at 06:13
10

I think this can be an answer

curl -0 -v -X POST http://www.example.com/api/users \
-H "Expect:" \
-H 'Content-Type: text/json; charset=utf-8' \
--data-raw '
{
    "field1": "test",
    "field2": {
        "foo": "bar"
    }
}'
kangkyu
  • 5,252
  • 3
  • 34
  • 36
  • I like this because it works well even with indentation and if one uses "" quotes, even variables can be used. – lnksz Aug 05 '22 at 16:25