atulmy/gql-query-builder

operationName not included as a root key of the query object

aethr opened this issue · 3 comments

aethr commented

We've been using gql-query-builder to replace hand-written queries in our service layer and so far it's working really well, thanks for creating this library.

I noticed recently that the GraphQL spec includes the following recommendation:

A standard GraphQL POST request should use the application/json content type, and include a JSON-encoded body of the following form:

{
  "query": "...",
  "operationName": "...",
  "variables": { "myVariable": "someValue", ... }
}

We've started work to stub out different gql queries and responses in our cypress test suite, and one of the recommendations is to use an explicit operationName in your queries, and then use this part of the request object to determine which response to send:

// Utility to match GraphQL mutation based on the operation name
export const hasOperationName = (req, operationName) => {
  const { body } = req
  return (
    body.hasOwnProperty('operationName') && body.operationName === operationName
  )
}

cypress.intercept('POST', '/graphql', req => {
  if (hasOperationName(req, 'getSite') {
    req.alias = 'getSite';
    req.send({ fixture: 'getSiteFixturre' });
  }
});

This code looks for the operationName in the root of the request body, and it seems this approach works well for a lot of developers, but isn't working for us because gql-query-builder only includes the operationName in the query itself.

For now we're working around this simply like:

  const gqlQuery = query({
    operation: 'site',
    variables: ...,
    fields: ...,
  }, null, { operationName: 'getSite' }));
  // manually add operationName
  gqlQuery.operationName = 'getSite';

However, if gql-query-builder did this for us we could use the intended syntax:

  const gqlQuery = query({
    operation: 'site',
    variables: ...,
    fields: ...,
  }, null, { operationName: 'getSite' });

Do you think this is something the library should support in the default adapter, and if so would you like me to make a pull request?

As per their docs:

If the query contains several named operations, an operationName query parameter can be used to control which one should be executed.

Are you looking at sending several named operations and need operationName?

aethr commented

Right now we're not attempting to send several named operations in the same document, we're just trying to add a bit of annotation to the queries we're sending to assist with tooling.

From a brief read of the current spec it seems like operationName is an optional field that should be fine to send even when there's only one named query.

However, it does make me wonder, does gql-query-builder allow us to specify operationName for each query in the document if an Array of queries is passed, like:

query([
  { operation: 'me', fields: ['name'] },
  { operation: 'site', fields: ['location'] },
]);

// {
//   query: "query { me { name } } { site { location } }",
// }

Since operationName is passed through a final config parameter I think it just gets applied to the first query in the document:

query([
  { operation: 'me', fields: ['name'] },
  { operation: 'site', fields: ['location'] },
], null, { operationName: 'getUser' });

// {
//   query: "query getUser { me { name } } { site { location } }",
// }

Perhaps operationName needs to be a field within each query definition, and then the operationName applied in config might be the one that's added to the root of the document.

query([
  { operation: 'me', fields: ['name'], operationName: 'getUser' },
  { operation: 'site', fields: ['location'], operationName: 'getSite' },
], null, { operationName: 'getUser' });

// {
//   query: "query getUser { me { name } } getSite { site { location } }",
//   operationName: "getUser",
// }

Apologies if this is wasting your time, I'm pretty new to GraphQL so still learning how all of these features are meant to be used.

I'm out of touch with recent evolution in GraphQL world myself, and would rather ask for help/suggestion on this one.