Yelp / yelp-fusion

Yelp Fusion API
https://yelp.com/developers
MIT License
403 stars 394 forks source link

Getting 400 error "Must Provide Query String" from Yelp GraphQL API (using Apollo Client) #278

Closed aleksdao closed 7 years ago

aleksdao commented 7 years ago

Overview

Description

Below are my request headers, as listed by the React Native Debugger's Chrome Dev Tools:

:method:POST
:path:/v3/graphql/
:scheme:https
accept:*/*
accept-encoding:gzip, deflate
accept-language:en_US
authorization:Bearer MY_ACCESS_TOKEN
content-length:175
content-type:application/json, application/graphql
origin:null
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) ReactNativeDebugger/0.7.4 Chrome/58.0.3029.110 Electron/1.7.6 Safari/537.36
x-devtools-request-id:34600.32

This works well in Postman, and I'm able to receive data from the Yelp GraphQL API as expected.

screen shot 2017-08-12 at 12 28 59 pm

More information

(Fill this section out if applicable (for things like bugs or questions))

Endpoint

Yelp GraphQL API endpoint (https://api.yelp.com/v3/graphql)

Parameters or Sample Request

query {
    business(id: "garaje-san-francisco") {
      name
      id
      location {
        city
      }
    }
  }

wrapped by Apollo's gql template tag

gql`
  query {
    business(id: "garaje-san-francisco") {
      name
      id
      location {
        city
      }
    }
  }
`

Response

{"errors":[{"message":"Must provide query string."}]}

Extra information

(Anything else you that you think might help us better resolve this)

tomelm commented 7 years ago

Hey @aleksdao, it looks like you're sending two values for the content type header. Could you try using only application/graphql and see if that works?

aleksdao commented 7 years ago

@tomelm Thanks for the suggestion Tom. Initially, I did set application/graphql as the only content-type header, but observed that when the request is made by the client, application/json seems to be getting added. Could this be a result of the React-Apollo client setting the application/json content-type header by default?

const networkInterface = createNetworkInterface({
  uri: 'https://api.yelp.com/v3/graphql',
});

networkInterface.use([
  {
    applyMiddleware(req, next) {
      if (!req.options.headers) {
        req.options.headers = {}; // Create the header object if needed.
      }

      req.options.headers.authorization = yelpAccessToken ? `Bearer ${yelpAccessToken}` : null;
      req.options.headers['content-type'] = 'application/graphql';
      req.options.headers['accept-language'] = 'en_US';
      next();
    },
  },
]);

const client = new ApolloClient({
  networkInterface,
});

I tested a bit more with Postman, and after setting both application/graphql, application/json content-type headers, I observed the same error message in the Yelp GraphQL response (Query string must be provided.... So the issue is being caused by an invalid header being sent with the request.

screen shot 2017-08-14 at 7 43 09 pm

Now I just need to find out whether I can override Apollo client's application/json content-header.

tomelm commented 7 years ago

I don't have a ton of experience with the Apollo client but I'd like to imagine that's possible. Are you using the regular, iOS, or Android one? It does look like you can set custom headers based on their auth examples: http://dev.apollodata.com/react/auth.html#Header

If you can, doing a JSON request might be better.

aleksdao commented 7 years ago

@tomelm I'm using the javascript Apollo client with a React Native application. Yup, I tried setting custom headers (as documented by my code samples above). Unfortunately, the net result is that application/graphql is appended to the default content-type: application/json header, resulting in a malformed header.

I think the expected behavior should be that whatever I set (in this case, application/graphql) overrides the default application/json.

I did post this to React-Apollo project and hoping someone there might have an answer (https://github.com/apollographql/react-apollo/issues/988). I'll definitely update here once there is a resolution

I'll give it a go with a JSON request :)

tomelm commented 7 years ago

Sounds good! Let me know what they say and if there's anything I can do to help or debug.

aleksdao commented 7 years ago

@tomelm It appears this was just a mistake on my part! If I'm reading this correctly (https://github.com/apollographql/apollo-client/blob/3b5045dfe74183fe060d2027e31317d890755b99/src/transport/networkInterface.ts#L189), the Apollo client calls JSON.stringify on the my query... so I should in fact be sending the default content-type: application/json header in my request.

After removing application/graphql override, this works as expected. Thanks for your help!