Search code examples
bashshellcurlstring-concatenation

Scripted concatenation of strings in curl command payload


I use curl to test an user account creation API as follows:

curl -s -X POST "https://$APISERVER/users" \
-H 'Content-Type: application/json' \
-d '{ \
"username": "'$NEWUSERNAME'", \
"firstName": "'$NEWUSERFIRSTNAME'", \
"lastName": "'$NEWUSERLASTNAME'", \
"displayName": "'$NEWUSERDISPLAYNAME'", \
"password": "'$NEWUSERPASSWORD'" \
}'

and the variables are supplied via command line arguments:

APISERVER=http://localhost:8080
NEWUSERNAME=$1
NEWUSERPASSWORD=$2
NEWUSERFIRSTNAME=$3
NEWUSERLASTNAME=$4

# Calculated variable
NEWUSERDISPLAYNAME="${NEWUSERFIRSTNAME} ${NEWUSERLASTNAME}"

An example invocation of the script is as follows: ./test-new-user.sh jdoe Hello123 John Doe, resulting in the following variable values:

NEWUSERNAME=jdoe
NEWUSERPASSWORD=Hello123
NEWUSERFIRSTNAME=John
NEWUSERLASTNAME=Doe

(I intended NEWUSERDISPLAYNAME to be set to "John Doe")

But I get back an exception from the server, because the payload in the curl command appears to be cut-off, incomplete or malformed.

JSON parse error: Unexpected end-of-input in VALUE_STRING\n at [Source: 
java.io.PushbackInputStream@2eda6052; line: 1, column: 293]; nested 
exception is com.fasterxml.jackson.databind.JsonMappingException: 
Unexpected end-of-input in VALUE_STRING\n at [Source: 
java.io.PushbackInputStream@2eda6052; line: 1, column: 293]\n at 
[Source: java.io.PushbackInputStream@2eda6052; line: 1, column: 142] 
(through reference chain: 
com.mycompany.api.pojos.NewUser[\"displayName\"])"

If I hard code value for displayName in the above curl command (as below), the user creation request goes through and works perfectly.

"displayName": "John Doe", \

I suspect it has to do with the space in displayName and how I insert the value for displayName using "'$NEWUSERDISPLAYNAME'". Is there a safe way to perform variable substitution in the curl command's POST request payload?


Solution

  • You need to quote shell variables:

    curl -s -X POST "https://$APISERVER/users" \
    -H 'Content-Type: application/json' \
    -d '{ \
    "username": "'"$NEWUSERNAME"'", \
    "firstName": "'"$NEWUSERFIRSTNAME"'", \
    "lastName": "'"$NEWUSERLASTNAME"'", \
    "displayName": "'"$NEWUSERDISPLAYNAME"'", \
    "password": "'"$NEWUSERPASSWORD"'" \
    }'
    

    In order to avoid excessive quoting, try this printf:

    printf -v json -- '{ "username": "%s", "firstName": "%s", "lastName": "%s", "displayName": "%s", "password": "%s" }' \
    "$NEWUSERNAME" "$NEWUSERFIRSTNAME" "$NEWUSERLASTNAME" "$NEWUSERDISPLAYNAME" "$NEWUSERPASSWORD"
    
    curl -s -X POST "https://$APISERVER/users" \
        -H 'Content-Type: application/json' \
        -d "$json"