hotmeatballsoup
hotmeatballsoup

Reputation: 625

Curl/GraphQL command failing with 200

I am trying to write a shell script that executes a curl against a GraphQL API and I've never interacted with GQL before. I am getting some strange errors and although I understand this community doesn't have access to the GQL server I was hoping someone could take a look at the script and make sure I'm not doing anything flagrantly wrong syntax-wise (both in the shell script layer as well as the GQL query itself).

My script:

#!/bin/bash

BSEE_WEB_SERVER_DNS=https://mybsee.example.com
BSEE_API_KEY=abc123

siteId=1
scanConfigId=456

runScanQuery='mutation CreateScheduleItem { create_schedule_item(input: {site_id: "$siteId" scan_configuration_ids: "$scanConfigId"}) { schedule_item { id } } }'
runScanVariables='{ "input": "site_id": $scanId }}'
runScanOperationName='CreateScheduleItem'

curl -i --request POST \
    --url $BSEE_WEB_SERVER_DNS/graphql/v1 \
    --header "Authorization: $BSEE_API_KEY" \
    --header 'Content-Type: application/json' \
    --data '{"query":"$runScanQuery","variables":{$runScanVariables},"operationName":"${runScanOperationName}"}'

And the output when I run the script off the terminal:

HTTP/2 200 

<OMITTED RESPONSE HEADERS>

{"errors":[{"message":"Invalid JSON : Unexpected character (\u0027$\u0027 (code 36)): was expecting double-quote to start field name, Line 1 Col 38","extensions":{"code":3}}]}%

I am omitting the HTTP response headers for security and brevity reasons.

I am wondering if my use of quotes/double-quotes is somehow wrong, or if there is anything about the nature of the GQL query itself (via curl) that looks off to anyone.

I verified with the team that manages the server that the HTTP 200 OK response code is correct. 200 shows that the request succeeded to the GQL API, but that GQL is responding with this error to indicate the query itself is incorrect.

Upvotes: 0

Views: 1407

Answers (3)

Andrey
Andrey

Reputation: 2078

Your error is completely unrelated to GraphQL. You really have wrong JSON.

Error message says Unexpected character (\u0027$\u0027 (code 36)): was expecting double-quote to start field name, Line 1 Col 38",

You can replace escaped \u0027 with apostrophe and you will get

Unexpected character ('$' (code 36)): was expecting double-quote to start field name, Line 1 Col 38",

So it hates dollar sign at position 38 in what you send as data to curl

data='{"query":"'"$runScanQuery"'","variables":'$runScanVariables'
                                                ^
                                               this

First - all field names and values in JSON should be wrapped with double quotes, not single.

Second - if you want curl to expand env variable, put it to double quotes, not single.

Upvotes: 0

Claudio
Claudio

Reputation: 3095

In GraphQL it's normal to always have 200 status code; client must check response body searching for failures.

The reason is simple: In REST, http is part of the protocol and status code has semantics but in GraphQL http is not part of the protocol, you can have GraphQL over serveral transport protocols:

  • http: typical scenario docs
  • WebSocket: does not provide any "status code like" payload. sample
  • MQTT: does not provide any "status code like" payload
  • ...

The only way that server tells you something (even failures) is the body.


In your case I suggest you jq to parse json via bash script searching error property.

Upvotes: 0

fedonev
fedonev

Reputation: 25739

We need to modify the GraphQL bits and fix the bash string quoting.

runScanQuery GraphQL operation

Fix the GraphQL syntax. Use a GraphQL operation name CreateScheduleItem with variables $site_id in the arguments input: { site_id: $siteId, scan_configuration_ids: $scanConfigId:

mutation CreateScheduleItem($site_id: String!, $scanConfigId: String!) {
  create_schedule_item(
    input: { site_id: $siteId, scan_configuration_ids: $scanConfigId }
  ) {
    schedule_item {
      id
    }
  }
}

runScanVariables: JSON

Our mutation expects two variables, which GraphQL will substitute into CreateScheduleItem($site_id: String!, $scanConfigId: String!). Provide the GraphQL variables as JSON. Here is the expected output after bash variable substitution:

{ "$site_id": "1", "$scanConfigId": "456" }

Get the bash quoting right

Finally, translate the inputs into bash-friendly syntax:

runScanQuery='mutation CreateScheduleItem($site_id: String!, $scanConfigId: String!) { create_schedule_item(input: {site_id: $siteId scan_configuration_ids: $scanConfigId}) { schedule_item { id } } }'
runScanVariables='{"$site_id":"'"$siteId"'","$scanConfigId":"'"$scanConfigId"'"}'  # no spaces!
runScanOperationName='CreateScheduleItem'
data='{"query":"'"$runScanQuery"'","variables":'$runScanVariables',"operationName":"'"$runScanOperationName"'"}'

Check our bash formats. Paste the terminal output into a code-aware editor like VSCode. Expect the editor to parse the output correctly.

echo $runScanQuery              # want string in graphql format
echo $runScanVariables          # want JSON
echo $data                      # want JSON

Edit: add a public API example

Here's a complete working example using the public Star Wars API:

#!/bin/bash
filmId=1
data='{"query":"query Query($filmId: ID) { film(filmID: $filmId) { title }}","variables":{"filmId":"'"$filmId"'"}}'

curl --location --request POST 'https://swapi-graphql.netlify.app/.netlify/functions/index' \
--header 'Content-Type: application/json' \
--data "$data"

Responds with {"data":{"film":{"title":"A New Hope"}}}.

Upvotes: 1

Related Questions