1

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.

Nagev
  • 4,017
  • 1
  • 29
  • 35
  • 2
    The `fetch` API is what you are looking for. But in a browser, you're just limited by the same origin policy, there's nothing you can do about that. – Bergi Feb 07 '20 at 16:32
  • 2
    `node-fetch` is server-based (because it's node). It isn't bound by the CORS policy, it can do whatever it wants. `fetch` ***is*** the browser equivalent for `fetch`. The problem is that browser JS ***is*** bound by CORS policy and there is no way to circumvent it outside of fetching from your own proxy server which you have to host. – zero298 Feb 07 '20 at 16:32
  • Thanks, I'm looking for code solutions. I know that there are Javascript GraphQL clients like relay and apollo, but I thought there must be a way to construct a simple query in JavaScript that I can run on the browser. But if the answer is "it's impossible and this is why...", I can accept that. I'll change my question to reflect what I want to achieve. – Nagev Feb 07 '20 at 16:43
  • Those libraries would be subject to exactly the same restriction. You need to fix the CORS policy of your server, use a proxy on your domain, or something else. Also, what exactly is the environment that your js code is running in? "*origin 'chrome-search://local-ntp'*" looks weird. – Bergi Feb 07 '20 at 16:55
  • 1
    @Nagev "How to do a simple GraphQL query in JavaScript" is a different question than your original question. What are you asking for, how to do a `GraphQL` query request using `JavaScript` in the browser? Or how to fix the `CORS` error that you're seeing in your browser when you try to make a `GraphQL` request? – goto1 Feb 07 '20 at 16:55
  • My question is the former: "How to do a simple GraphQL query in JavaScript". I don't care about CORS really, it was just a result of my first attempt, which was likely not in the right direction. – Nagev Feb 07 '20 at 16:57
  • @Nagev Take a look here at **#3** and **#4** - https://blog.apollographql.com/4-simple-ways-to-call-a-graphql-api-a6807bcdb355. Keep in mind, this will not fix your `CORS` issues, so you still won't be able to make that request from a web browser. – goto1 Feb 07 '20 at 17:00
  • Thanks, it's just that I know for a fact that there are web applications (that run on any browser) using the exact same API, so there must be a way. I'm new to this, so I'm trying to find out what's the core of the solution. Buf if the community feels that there's no value in this question, please feel free to close it! – Nagev Feb 07 '20 at 17:10

1 Answers1

3

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.

Daniel Rearden
  • 58,313
  • 8
  • 105
  • 113