Sending nested JSON object using HTTPie - json

I am trying to use HTTPie to parse to send some nested JSON object, but I can not find how. It is pretty clear how to send a JSON object but not a nested one such as
{ "user": { "name": "john"
"age": 10 } }

Update for HTTPie 3.0 released in January 2022:
There’s now built-in support for nested JSON using the HTTPie language:
$ http pie.dev/post \
tool[name]=HTTPie \
tool[about][homepage]=httpie.io \
tool[about][mission]='Make APIs simple and intuitive' \
tool[platforms][]=terminal \
tool[platforms][]=desktop \
tool[platforms][]=web \
tool[platforms][]=mobile
{
"tool": {
"name": "HTTPie",
"about": {
"mission": "Make APIs simple and intuitive",
"homepage": "httpie.io"
},
"platforms": [
"terminal",
"desktop",
"web",
"mobile"
]
}
}
You can learn more about nested JSON in the docs: https://httpie.io/docs/cli/nested-json
Old answer for HTTPie older than 3.0:
You can pass the whole JSON via stdin:
$ echo '{ "user": { "name": "john", "age": 10 } }' | http httpbin.org/post
Or specify the raw JSON as value with :=:
$ http httpbin.org/post user:='{"name": "john", "age": 10 }'

I like this way:
$ http PUT localhost:8080/user <<<'{ "user": { "name": "john", "age": 10 }}'
It is preferrable because it has the same prefix as the related commands, and so it is convenient to find the commands with Ctrl+R in bash:
$ http localhost:8080/user/all
$ http GET localhost:8080/user/all # the same as the previous
$ http DELETE localhost:8080/user/234
If you have fishshell, which doesn't have Here Strings, I can propose the following workaround:
~> function tmp; set f (mktemp); echo $argv > "$f"; echo $f; end
~> http POST localhost:8080/user < (tmp '{ "user": { "name": "john", "age": 10 }}')

Another approach mentioned in the httpie docs is using a JSON file; this has worked well for me for payloads that are more verbose and deeply nested.
http POST httpbin.org/post < post.json

On Windows 10 (cmd.exe) the syntax is a little bit different due to quoting rules. Properties/strings need to be surrounded by double quotes.
http -v post https://postman-echo.com/post address:="{""city"":""london""}"
POST /post HTTP/1.1
Content-Type: application/json
Host: postman-echo.com
User-Agent: HTTPie/2.3.0
{
"address": {
"city": "london"
}
}
You can also send the whole object using echo, and without double quoting.
echo {"address": {"city":"london"} } | http -v post https://postman-echo.com/post

Related

Get JSON value from curl request

I have a Nexus Repository server where my artifacts are stored. I want to write a shell script to download artifacts from here. When using the curl request curl --user username:password -X GET "http://your_ip:your_port/service/rest/v1/search?repository=your_repository" -H "accept: application/json" I get a list of the items in my repository which looks like this:
{
"items": [
{
"id": "dGVzdC1hcHA6ZDM1MTBiN2FkMThkODJjZGU1NjNhMWVlMWFmOWIwMGQ",
"repository": "test-app",
"format": "maven2",
"group": "no.ahj",
"name": "test-app",
"version": "1.0-20190715.130341-2",
"assets": [
{
"downloadUrl": "http://192.168.56.2:8081/repository/test-app/no/ahj/test-app/1.0-SNAPSHOT/test-app-1.0-20190715.130341-2.pom",
"path": "no/ahj/test-app/1.0-SNAPSHOT/test-app-1.0-20190715.130341-2.pom",
"id": "dGVzdC1hcHA6Yzc3MDE2OWMwYjJlM2VkODU0MGMyOGEwOWQ0Njk4ZTQ",
"repository": "test-app",
"format": "maven2",
"checksum": {
"sha1": "5fd032774dd3ae6fbbd6484b3dc6ef2582d9b397",
"md5": "3a6aa8e295a734fdb8a8df782c0a14d5"
}
},
I would like my shell script to run this curl request, extract the value from the downloadURL field, store it in some variable and then use wget with this variable to download the file. So my question is this: How can I take the URL from downloadURL and store/use it in my shell script?
A way to parse it with likely no external dependencies (as python is installed by default on most Linux distributions) is just to use python:
user#host ~ % JSON=$(curl --user username:password -X GET "http://your_ip:your_port/service/rest/v1/search?repository=your_repository" -H "accept: application/json")
user#host ~ % echo $JSON | python -c 'import sys, json; print(json.load(sys.stdin)["items"][0]["assets"][0]["downloadUrl"])'
http://192.168.56.2:8081/repository/test-app/no/ahj/test-app/1.0-SNAPSHOT/test-app-1.0-20190715.130341-2.pom
If you are going to do a lot of JSON parsing in this script, it may be worth considering writing the entire script in Python, too, instead of shell script.

How to iterate objects from JSON array file in batch script

I have a windows batch script to perform POST request using curl and reads the data from JSON file, it works fine with only a single object in the file and it looks like this.
curl -u username#password -H "Content-Type: application/json" -d #file.json http://apiurl.com
and the json file is this:
{
"name": "Empty name",
"properties": {
"active": "True",
"subcity_zone": "East Hararge",
"woreda": "Meta"
}
}
But now I want to send the request each object in the array by iterating each item. So, How do I iterate each JSON object from the file?
Here is what the new JSON array file looks like:
[{
"name": "test facility I",
"properties": {
"active": "True",
"city": "",
"subcity_zone": "East Hararge",
"woreda": "Meta"
}
},
{
"name": "test facility II",
"properties": {
"active": "True",
"subcity_zone": "East Hararge",
"woreda": "Girawa"
}
}]
Using jq:
jq -c '.[]' file | while read js; do
curl -u username#password -H "Content-Type: application/json" -d #<(echo "$js") http://apiurl.com
done
The jq command extracts the each object in one line that is read by read command into the $js variable.
The <(echo "$js") creates a temporary file that is passed to curl.

Why is my jq failing on my JSON?

Haven't used jq before but I'm wanting to build a shell script that will get a JSON response and extract just the values. To learn I thought I would try on my blog's WP API but for some reason I'm getting an error of:
jq: error (at :322): Cannot index array with string "slug"
When researching for and testing previous questions:
jq: Cannot index array with string
jq is sed for JSON
JSON array to bash variables using jq
How to use jq in a shell pipeline?
How to extract data from a JSON file
The above reading I've tried to code:
URL="http://foobar.com"
RESPONSE=$(curl -so /dev/null -w "%{http_code}" $URL)
WPAPI="/wp-json/wp/v2"
IDENTIFIER="categories"
if (("$RESPONSE" == 200)); then
curl -s {$URL$WPAPI"/"$IDENTIFIER"/"} | jq '.' >> $IDENTIFIER.json
result=$(jq .slug $IDENTIFIER.json)
echo $result
else
echo "Not returned status 200";
fi
An additional attempt changing the jq after the curl:
curl -s {$URL$WPAPI"/"$IDENTIFIER"/"} | jq '.' | $IDENTIFIER.json
result=(jq -r '.slug' $IDENTIFIER.json)
echo $result
I can modify the uncompress with the python JSON tool:
result=(curl -s {$URL$WPAPI"/"$IDENTIFIER"/"} | python -m json.tool > $IDENTIFIER.json)
I can save the JSON to a file but when I use jq I cannot get just the slug and here are my other trys:
catCalled=$(curl -s {$URL$WPAPI"/"$IDENTIFIER"/"} | python -m json.tool | ./jq -r '.slug')
echo $catCalled
My end goal is to try to use jq in a shell script and build a slug array with jq. What am I doing wrong in my jq and can I use jq on a string without creating a file?
Return from curl after uncompress per comment request:
[
{
"id": 4,
"count": 18,
"description": "",
"link": "http://foobar.com/category/foo/",
"name": "Foo",
"slug": "foo",
"taxonomy": "category",
},
{
"id": 8,
"count": 9,
"description": "",
"link": "http://foobar.com/category/bar/",
"name": "Bar",
"slug": "bar",
"taxonomy": "category",
},
{
"id": 5,
"count": 1,
"description": "",
"link": "http://foobar.com/category/mon/",
"name": "Mon",
"slug": "mon",
"taxonomy": "category",
},
{
"id": 11,
"count": 8,
"description": "",
"link": "http://foobar.com/category/fort/",
"name": "Fort",
"slug": "fort",
"taxonomy": "category",
}
]
eventually my goal is trying to get the name of the slug's into an array like:
catArray=('foo','bar','mon', 'fort')
There are 2 issues here:
slug is not a root level element in your example json. The root level element is an array. If you want to access the slug property of each element of the array, you can do so like this:
jq '.[].slug' $IDENTIFIER.json
Your example json has trailing commas after the last property of each array element. Remove the commas after "taxonomy": "category".
If I take your sample json, remove the errant commas, save it to a plain text file called test.json and run the following command:
jq '.[].slug' test.json
I get the following output:
"foo"
"bar"
"mon"
"fort"
Preprocessing
Unfortunately, the JSON-like data shown as having been produced by curl is not strictly JSON. jq does not have a "relaxed JSON" mode, so in order to use jq, you will have to preprocess the JSON-like data, e.g. using hjson (see http://hjson.org/):
$ hjson -j input.qjson > input.json
jq
With the JSON in input.json:
$ jq -c 'map(.slug)' input.json
["foo","bar","mon","fort"]
your string is not json, notice how the last member of your objects ends with a comma,
{foo:"bar",baz:9,}
this is legal in javascript, but it's illegal in json. if you are supposed to be receiving json from that endpoint, then contact the people behind it and tell them to fix the bug (it's breaking the json specs by ending objects's last member with a comma, which is illegal in json.) - until it's fixed, i guess you can patch it with a little regex, but it's a dirty quickfix, and probably not very reliable, but running it through
perl -p -0777 -e 's/\"\,\s*}/\"}/g;' makes it legal json..

How to send JSON file as part of request body in CURL POST command

I am using CURL command line to send HTTP POST to a web service. I want to include a file's contents as a PART of the body of the POST command. Is this possible? I know I can send a file as the entire body as answered here. But I only want a part of the body to be the content of the file.
For example
curl -d '{ "name": "rahul", "speed": "fast", "data": { "number": 1, "letter": "abd", "letter2": "efg"} }' 'http://...'
Here I only want data as the file's content. Not the entire body. How can I do this?
Set a variable to contain the file contents:
data=$(cat /path/to/file)
then substitute it into the JSON:
curl -d '{ "name": "rahul", "speed": "fast", "data": "'$data'" }' 'http://...'
You accepted #Barmar's answer, but for anyone reading this, #Barmar switched the double- and single-quotes, which will cause the command to not work as intended.
The following works:
data="$(cat filename)" && \
curl -d '{ "name": "rahul", "speed": "fast", "data": "'$data'" }' 'http://...'
Notice that the $data variable is surrounded by single-quotes first, then double-quotes.

cURL Response JSON RestAPI

I need to delete some wrong data, inserted in a lot of processes, and I need to figure if this is possible with cURL and rest API, with a script in sh, batch or something like this:
curl -u admin:admin -i -H "Accept: application/json" -X GET "http://json_bpm.com/wle/v1/service/6112449?action=getData&fields=context"
First I just need the result map.
Output:
{"status":"200","data":{"result":"{\"context\":{\"name\":\"xxx\" (...)
"resultMap":{"context":{"name\":"xxx\" (...) }}}
Because I need to remove the userDelete array (see below) for thousands of processes, and set this again using curl. If you know how to remove arrays from JSON too, you're the man. :)
{
"context": {
"name": "Change Process",
"startUser": {
"user": "0001"
},
"endUser": {
"user": "0001"
},
"userDelete": {
"user": "0002"
},
"origin": "GUI",
"userAction": "Change Process"
}
}