jamiet
jamiet

Reputation: 12264

How do I check the HTTP status code and also parse the payload

Imagine I have the following code in a bash script:

curl -s https://cat-fact.herokuapp.com/facts/random?animal=cat | jq .

Notice that I wish to display the payload of the response by passing it to jq.

Now suppose sometimes those curls sometimes return a 404, in such cases my script currently still succeeds so what I need to do is check the return code and exit 1 as appropriate (e.g. for a 404 or 503). I've googled around and found https://superuser.com/a/442395/722402 which suggests --write-out "%{http_code}" might be useful however that simply prints the http_code after printing the payload:

curl -s --write-out "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat | jq .

$ curl -s --write-out "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat | jq .  
{  
  "_id": "591f98783b90f7150a19c1ab",  
  "__v": 0,  
  "text": "Cats and kittens should be acquired in pairs whenever possible as cat families interact best in pairs.",  
  "updatedAt": "2018-12-05T05:56:30.384Z",  
  "createdAt": "2018-01-04T01:10:54.673Z",  
  "deleted": false,  
  "type": "cat",  
  "source": "api",  
  "used": false  
}  
200

What I actually want to is still output the payload, but still be able to check the http status code and fail accordingly. I'm a bash noob so am having trouble figuring this out. Help please?

I'm using a Mac by the way, not sure if that matters or not (I'm vaguely aware that some commands work differently on Mac)


Update, I've pieced this together which sorta works. I think. Its not very elegant though, I'm looking for something better.

func() {
   echo "${@:1:$#-1}";
}
response=$(curl -s --write-out "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat | jq .) 
http_code=$(echo $response | awk '{print $NF}')
func $response | jq .
if [ $http_code == "503" ]; then
    echo "Exiting with error due to 503"
    exit 1
elif [ $http_code == "404" ]; then
    echo "Exiting with error due to 404"
    exit 1
fi

Upvotes: 1

Views: 1889

Answers (3)

PerseP
PerseP

Reputation: 1197

Borrowing from here you can do:

#!/bin/bash

result=$(curl -s --write-out "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat)

http_code="${result: -3}"
response="${result:0:${#result}-3}" 
echo "Response code: " $http_code
echo "Response: " 
echo $response | jq

Where ${result: -3} is the 3rd index starting from the right of the string till the end. This ${result: -3:3} also would work: Index -3 with length 3

${#result} gives us the length of the string

${result:0:${#result}-3} from the beginning of result to the end minus 3 from the http_status code

The site cat-fact.herokuapp.com isn't working now so I had to test it with another site

Upvotes: 0

Matias Barrios
Matias Barrios

Reputation: 5056

This is my attempt. Hope it works for you too.

#!/bin/bash

result=$( curl -i -s 'https://cat-fact.herokuapp.com/facts/random?animal=cat'  )


status=$( echo "$result" | grep -E '^HTTPS?/[1-9][.][1-9] [1-9][0-9][0-9]' | grep -o ' [1-9][0-9][0-9] ')
payload=$( echo "$result" | sed -n '/^\s*$/,//{/^\s*$/ !p}' )

echo "STATUS : $status"
echo "PAYLOAD : $payload"

Output

STATUS :  200
PAYLOAD : {"_id":"591f98803b90f7150a19c23f","__v":0,"text":"Cats can't taste sweets.","updatedAt":"2018-12-05T05:56:30.384Z","createdAt":"2018-01-04T01:10:54.673Z","deleted":false,"type":"cat","source":"api","used":false}

AWK version

payload=$( echo "$result" | awk '{ if( $0 ~ /^\s*$/ ){ c_p = 1 ; next; } if (c_p) { print $0} }' )

Regards!

EDIT : I have simplified this even more by using the -i flag

EDIT II : Removed empty line from payload

EDIT III : Included an awk method to extract the payload in case sed is problematic

Upvotes: 1

OkieOth
OkieOth

Reputation: 3704

What about this. It uses a temporary file. Seems me a bit complicated but it separates your content.

# copy/paste doesn't work with the following
curl -s --write-out \
   "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat | \ 
   tee test.txt | \      # split output to file and stdout
   sed -e 's-.*\}--' | \ # remove everything before last '}'
   grep 200  && \       # try to find string 200, only in success next step is done
   echo && \            # a new-line to juice-up the output
   cat test.txt | \     # 
   sed 's-}.*$-}-' | \  # removes the last line with status
   jq                   # formmat json

Here a copy/paste version

curl -s --write-out "%{http_code}" https://cat-fact.herokuapp.com/facts/random?animal=cat | tee test.txt | sed -e 's-.*\}--' | grep 200  && echo && cat test.txt | sed 's-}.*$-}-' | jq

Upvotes: 2

Related Questions