Search code examples
javascriptgraphql

How to do a simple GraphQL query in JavaScript


If I do a GraphQL query usinge node-fetch or curl I get back the expected results. For example, if I have a file gquery.js with the following code:

const fetch = require("node-fetch")
fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Api-Service-Key': '123456789077',
  },
  body: JSON.stringify({query: "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }",
  variables: { "fruitId": "ikttwwwbvn7" }})
})
  .then(r => r.json())
  .then(data => console.log('data returned:', data));

And on my Ubuntu machine I just run $node gquery.js I get back a result. I'll also get a result if I use plain curl, e.g.:

curl -H 'Content-Type: application/json' -X POST -H "X-Api-Service-Key: 123456789077" https://api.example.com/graphql -d '{ "query": "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }", "variables": { "fruitId": "ikttwwwbvn7" }}'

However, if I just use fetch on Chrome, e.g.:

fetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Api-Service-Key': '123456789077',
  },
  body: JSON.stringify({query: "query($fruitId: String!) { fruit(id: $fruitId) { id, name } }",
  variables: { "fruitId": "ikttwwwbvn7" }})
})
  .then(r => r.json())
  .then(data => console.log('data returned:', data));

I get an error:

Access to fetch at 'https://api.example.com/graphql' from origin 'chrome-search://local-ntp' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Note: My endpoint is actually different, but otherwise this example is essentially the same as what I have.

I had a look at a related question, but answers seem to suggest that this cannot be resolved on the client side only. But the fact that I can use curl and node successfully tells me that I just don't have the right code.

To be clear, I don't really care about fetch. I'm happy to use any standalone Javascript solution that does not require the use of a client like apollo or relay.


Solution

  • There's no way to get around the same-origin policy enforced by browsers. You don't encounter the same issue when sending your request through curl or node because the same-origin policy is not enforced in those contexts. It is always enforced in the browser unless you explicitly disable it. Preventing cross-domain requests is an import security measure, though, so disabling it is generally inadvisable.

    There's nothing magical about how GraphQL clients like Apollo work. They still use fetch under the hood. If you're hitting a CORS issue using fetch, you'd hit the same issue using Apollo or any other browser-based client. If you use a standalone client like Postman or Altair, you won't because, again, you're not dealing with a browser.

    As suggested in the post you linked, this is an issue that has to be addressed on the server-side. If you're not making requests to your own server, the only viable workaround is to utilize a proxy. You can utilize an existing one or run your own.