3285
votes

I use Ubuntu and installed cURL on it. I want to test my Spring REST application with cURL. I wrote my POST code at the Java side. However, I want to test it with cURL. I am trying to post a JSON data. Example data is like this:

{"value":"30","type":"Tip 3","targetModule":"Target 3","configurationGroup":null,"name":"Configuration Deneme 3","description":null,"identity":"Configuration Deneme 3","version":0,"systemId":3,"active":true}

I use this command:

curl -i \
    -H "Accept: application/json" \
    -H "X-HTTP-Method-Override: PUT" \
    -X POST -d "value":"30","type":"Tip 3","targetModule":"Target 3","configurationGroup":null,"name":"Configuration Deneme 3","description":null,"identity":"Configuration Deneme 3","version":0,"systemId":3,"active":true \
    http://localhost:8080/xx/xxx/xxxx

It returns this error:

HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 24 Aug 2011 08:50:17 GMT

The error description is this:

The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().

Tomcat log: "POST /ui/webapp/conf/clear HTTP/1.1" 415 1051

What is the right format of the cURL command?

This is my Java side PUT code (I have tested GET and DELETE and they work):

@RequestMapping(method = RequestMethod.PUT)
public Configuration updateConfiguration(HttpServletResponse response, @RequestBody Configuration configuration) { //consider @Valid tag
    configuration.setName("PUT worked");
    //todo If error occurs response.sendError(HttpServletResponse.SC_NOT_FOUND);
    return configuration;
}
25
checkout the link for spring 3.2.0 post requests.AmirHd
There is a nice post Using Curl For Ad Hoc Testing Of RESTful Microservices which covers this with multiple examples.upitau

25 Answers

5034
votes

You need to set your content-type to application/json. But -d (or --data) sends the Content-Type application/x-www-form-urlencoded, which is not accepted on Spring's side.

Looking at the curl man page, I think you can use -H (or --header):

-H "Content-Type: application/json"

Full example:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"username":"xyz","password":"xyz"}' \
  http://localhost:3000/api/login

(-H is short for --header, -d for --data)

Note that -request POST is optional if you use -d, as the -d flag implies a POST request.


On Windows, things are slightly different. See the comment thread.

656
votes

Try to put your data in a file, say body.json and then use

curl -H "Content-Type: application/json" --data @body.json http://localhost:8080/ui/webapp/conf
120
votes

For Windows, having a single quote for the -d value did not work for me, but it did work after changing to double quote. Also I needed to escape double quotes inside curly brackets.

That is, the following did not work:

curl -i -X POST -H "Content-Type: application/json" -d '{"key":"val"}' http://localhost:8080/appname/path

But the following worked:

curl -i -X POST -H "Content-Type: application/json" -d "{\"key\":\"val\"}" http://localhost:8080/appname/path
109
votes

You might find resty useful: https://github.com/micha/resty

It's a wrapper round CURL which simplifies command line REST requests. You point it to your API endpoint, and it gives you PUT and POST commands. (Examples adapted from the homepage)

$ resty http://127.0.0.1:8080/data #Sets up resty to point at your endpoing
$ GET /blogs.json                  #Gets http://127.0.0.1:8080/data/blogs.json
                                   #Put JSON
$ PUT /blogs/2.json '{"id" : 2, "title" : "updated post", "body" : "This is the new."}'
                                   # POST JSON from a file
$ POST /blogs/5.json < /tmp/blog.json

Also, it's often still necessary to add the Content Type headers. You can do this once, though, to set a default, of add config files per-method per-site: Setting default RESTY options

101
votes

It worked for me using:

curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"id":100}' http://localhost/api/postJsonReader.do

It was happily mapped to the Spring controller:

@RequestMapping(value = "/postJsonReader", method = RequestMethod.POST)
public @ResponseBody String processPostJsonData(@RequestBody IdOnly idOnly) throws Exception {
        logger.debug("JsonReaderController hit! Reading JSON data!"+idOnly.getId());
        return "JSON Received";
}

IdOnly is a simple POJO with an id property.

58
votes

As an example, create a JSON file, params.json, and add this content to it:

[
    {
        "environment": "Devel",
        "description": "Machine for test, please do not delete!"
    }
]

Then you run this command:

curl -v -H "Content-Type: application/json" -X POST --data @params.json -u your_username:your_password http://localhost:8000/env/add_server
45
votes

You can use postman to convert to CURLenter image description here

enter image description here

44
votes

I just run into the same problem. I could solve it by specifying

-H "Content-Type: application/json; charset=UTF-8"
39
votes

This worked well for me.

curl -X POST --data @json_out.txt http://localhost:8080/

Where,

-X Means the http verb.

--data Means the data you want to send.

37
votes

You can use Postman with its intuitive GUI to assemble your cURL command.

  1. Install and Start Postman
  2. Type in your URL, Post Body, Request Headers etc. pp.
  3. Click on Code
  4. Select cURL from the drop-down list
  5. copy & paste your cURL command

Note: There are several options for automated request generation in the drop-down list, which is why I thought my post was neccessary in the first place.

30
votes

Using CURL Windows, try this:

curl -X POST -H "Content-Type:application/json" -d "{\"firstName\": \"blablabla\",\"lastName\": \"dummy\",\"id\": \"123456\"}" http-host/_ah/api/employeeendpoint/v1/employee
30
votes

HTTPie is a recommended alternative to curl because you can do just

$ http POST http://example.com/some/endpoint name=value name1=value1

It speaks JSON by default and will handle both setting the necessary header for you as well encoding data as valid JSON. There is also:

Some-Header:value

for headers, and

name==value

for query string parameters. If you have a large chunk of data, you can also read it from a file have it be JSON encoded:

 [email protected]
22
votes

If you're testing a lot of JSON send/responses against a RESTful interface, you may want to check out the Postman plug-in for Chrome (which allows you to manually define web service tests) and its Node.js-based Newman command-line companion (which allows you to automate tests against "collections" of Postman tests.) Both free and open!

22
votes

This worked well for me, additionally using BASIC authentication:

curl -v --proxy '' --basic -u Administrator:password -X POST -H "Content-Type: application/json"
        --data-binary '{"value":"30","type":"Tip 3","targetModule":"Target 3","configurationGroup":null,"name":"Configuration Deneme 3","description":null,"identity":"Configuration Deneme 3","version":0,"systemId":3,"active":true}'
        http://httpbin.org/post

Of course, you should never use BASIC authentication without SSL and a checked certificate.

I ran into this again today, using Cygwin's cURL 7.49.1 for Windows... And when using --data or --data-binary with a JSON argument, cURL got confused and would interpret the {} in the JSON as a URL template. Adding a -g argument to turn off cURL globbing fixed that.

See also Passing a URL with brackets to curl.

20
votes

You could also put your JSON content in a file and pass it to curl using the --upload-file option via standard input, like this:

 echo 'my.awesome.json.function({"do" : "whatever"})' | curl -X POST "http://url" -T -
17
votes

This worked for me:

curl -H "Content-Type: application/json" -X POST -d @./my_json_body.txt http://192.168.1.1/json
17
votes

I know, a lot has been answered to this question but wanted to share where I had the issue of:

curl -X POST http://your-server-end-point -H "Content-Type: application/json" -d @path-of-your-json-file.json

See, I did everything right, Only one thing - "@" I missed before the JSON file path.

I found one relevant go-to document on internet - https://gist.github.com/subfuzion/08c5d85437d5d4f00e58

Hope that might help the few. thanks

14
votes

Here is another way to do it, if you have dynamic data to be included.

#!/bin/bash

version=$1
text=$2
branch=$(git rev-parse --abbrev-ref HEAD)
repo_full_name=$(git config --get remote.origin.url | sed 's/.*:\/\/github.com\///;s/.git$//')
token=$(git config --global github.token)

generate_post_data()
{
  cat <<EOF
{
  "tag_name": "$version",
  "target_commitish": "$branch",
  "name": "$version",
  "body": "$text",
  "draft": false,
  "prerelease": false
}
EOF
}

echo "Create release $version for repo: $repo_full_name branch: $branch"
curl --data "$(generate_post_data)" "https://api.github.com/repos/$repo_full_name/releases?access_token=$token"
13
votes

I am using the below format to test with a web server.

use -F 'json data'

Let's assume this JSON dict format:

{
    'comment': {
        'who':'some_one',
        'desc' : 'get it'
    }
}

Full example

curl -XPOST your_address/api -F comment='{"who":"some_one", "desc":"get it"}'
13
votes

Use -d option to add payload

curl -X POST \
http://<host>:<port>/<path> \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"foo": "bar",
"lorem": "ipsum"
}'

In addition:

use -X POST to use POST method

use -H 'Accept: application/json' to add accept type header

use -H 'Content-Type: application/json' to add content type header

11
votes

This worked for me for on Windows10

curl -d "{"""owner""":"""sasdasdasdasd"""}" -H "Content-Type: application/json" -X  PUT http://localhost:8080/api/changeowner/CAR4
9
votes

I made a tool called fetcher for this. It can send requests and format curl snippets:

Here's an example:

enter image description here

Example output:

curl -XGET -H "Accept: application/json" -d "{\"value\":\"30\",\"type\":\"Tip 3\",\"targetModule\":\"Target 3\",\"configurationGroup\":null,\"name\":\"Configuration Deneme 3\",\"description\":null,\"identity\":\"Configuration Deneme 3\",\"version\":0,\"systemId\":3,\"active\":true}" "http://localhost:8080/xx/xxx/xxxx"
4
votes

If you configure the SWAGGER to your spring boot application, and invoke any API from your application there you can see that CURL Request as well.

I think this is the easy way of generating the requests through the CURL.

0
votes

Based on https://stackoverflow.com/a/57369772/2391795 answer, here is what I did to this on GitHub Actions. It was a bit tricky due to the EOF tag.

My goal was to send an HTTP call once a Vercel deployment was finished (similar to a webhook).

Hoping this real-world example might help other people.

  send-webhook-callback-once-deployment-ready:
    name: Invoke webhook callback url defined by the customer (Ubuntu 18.04)
    runs-on: ubuntu-18.04
    needs: await-for-vercel-deployment
    steps:
      - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout
      - name: Expose GitHub slug/short variables # See https://github.com/rlespinasse/github-slug-action#exposed-github-environment-variables
        uses: rlespinasse/[email protected] # See https://github.com/rlespinasse/github-slug-action
      - name: Expose git environment variables and call webhook (if provided)
        # Workflow overview:
        #  - Resolves webhook url from customer config file
        #  - If a webhook url was defined, send a
        run: |
          MANUAL_TRIGGER_CUSTOMER="${{ github.event.inputs.customer}}"
          CUSTOMER_REF_TO_DEPLOY="${MANUAL_TRIGGER_CUSTOMER:-$(cat vercel.json | jq --raw-output '.build.env.NEXT_PUBLIC_CUSTOMER_REF')}"

          VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK=$(cat vercel.$CUSTOMER_REF_TO_DEPLOY.staging.json | jq --raw-output '.build.env.VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK')

          # Checking if a webhook url is defined
          if [ -n "$VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK" ]; then
            # Run script that populates git-related variables as ENV variables
            echo "Running script populate-git-env.sh"
            . ./scripts/populate-git-env.sh

            echo "Resolved git variables:"
            echo "'GIT_COMMIT_SHA': $GIT_COMMIT_SHA"
            echo "'GIT_COMMIT_REF': $GIT_COMMIT_REF"
            echo "'GIT_COMMIT_TAGS': $GIT_COMMIT_TAGS"

            # Generates JSON using a bash function - See https://stackoverflow.com/a/57369772/2391795
            # "End Of File" must be at the beginning of the line with no space/tab before or after - See https://stackoverflow.com/a/12909284/2391795
            # But, when executed by GitHub Action, it must be inside the "run" section instead
            generate_post_data() {
              cat <<EOF
            {
              "MANUAL_TRIGGER_CUSTOMER": "${MANUAL_TRIGGER_CUSTOMER}",
              "CUSTOMER_REF": "${CUSTOMER_REF_TO_DEPLOY}",
              "STAGE": "staging",
              "GIT_COMMIT_SHA": "${GIT_COMMIT_SHA}",
              "GIT_COMMIT_REF": "${GIT_COMMIT_REF}",
              "GIT_COMMIT_TAGS": "${GIT_COMMIT_TAGS}",
              "GITHUB_REF_SLUG": "${GITHUB_REF_SLUG}",
              "GITHUB_HEAD_REF_SLUG": "${GITHUB_HEAD_REF_SLUG}",
              "GITHUB_BASE_REF_SLUG": "${GITHUB_BASE_REF_SLUG}",
              "GITHUB_EVENT_REF_SLUG": "${GITHUB_EVENT_REF_SLUG}",
              "GITHUB_REPOSITORY_SLUG": "${GITHUB_REPOSITORY_SLUG}",
              "GITHUB_REF_SLUG_URL": "${GITHUB_REF_SLUG_URL}",
              "GITHUB_HEAD_REF_SLUG_URL": "${GITHUB_HEAD_REF_SLUG_URL}",
              "GITHUB_BASE_REF_SLUG_URL": "${GITHUB_BASE_REF_SLUG_URL}",
              "GITHUB_EVENT_REF_SLUG_URL": "${GITHUB_EVENT_REF_SLUG_URL}",
              "GITHUB_REPOSITORY_SLUG_URL": "${GITHUB_REPOSITORY_SLUG_URL}",
              "GITHUB_SHA_SHORT": "${GITHUB_SHA_SHORT}"
            }
          EOF
            }

            echo "Print generate_post_data():"
            echo "$(generate_post_data)"

            echo "Calling webhook at '$VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK'"
            echo "Sending HTTP request (curl):"
            curl POST \
              "$VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK" \
              -vs \
              --header "Accept: application/json" \
              --header "Content-type: application/json" \
              --data "$(generate_post_data)" \
              2>&1 | sed '/^* /d; /bytes data]$/d; s/> //; s/< //'

            # XXX See https://stackoverflow.com/a/54225157/2391795
            # -vs - add headers (-v) but remove progress bar (-s)
            # 2>&1 - combine stdout and stderr into single stdout
            # sed - edit response produced by curl using the commands below
            #   /^* /d - remove lines starting with '* ' (technical info)
            #   /bytes data]$/d - remove lines ending with 'bytes data]' (technical info)
            #   s/> // - remove '> ' prefix
            #   s/< // - remove '< ' prefix

          else
            echo "No webhook url defined in 'vercel.$CUSTOMER_REF_TO_DEPLOY.staging.json:.build.env.VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK' (found '$VERCEL_DEPLOYMENT_COMPLETED_WEBHOOK')"
          fi
-8
votes

You can pass the extension of the format you want as the end of the url. like http://localhost:8080/xx/xxx/xxxx.json

or

http://localhost:8080/xx/xxx/xxxx.xml

Note: you need to add jackson and jaxb maven dependencies in your pom.