How to parse GraphQL request string into an object
Asked Answered
W

4

34

I am running Apollo lambda server for GraphQL. I want to intercept the GraphQL query/mutation from the POST request body and parse it so I can find out which query/mutation the request is asking for. The environment is Node.js.

The request isn't JSON, it's GraphQL query language. I've looked around to try and find a way to parse this into an object that I can navigate but I'm drawing a blank.

The Apollo server must be parsing it somehow to direct the request. Does anyone know a library that will do this or pointers on how I can parse the request? Examples of request bodies and what I want to retrieve below.

{"query":"{\n  qQueryEndpoint {\n    id\n  }\n}","variables":null,"operationName":null}

I would like to identify that this is a query and that qQueryEndpoint is being asked for.

{"query":"mutation {\\n  saveSomething {\\n    id\\n  }\\n}","variables":null}

I would like to identify that this is a mutation and the saveSomething mutation is being used.

My first idea for this is to strip out the line breaks and try and use regular expressions to parse the request but it feels like a very brittle solution.

Wharf answered 1/3, 2018 at 10:9 Comment(8)
Possible duplicate of What is JavaScript AST, how to play with it?Kokura
My question was wrong. The request is GraphQL query language, not AST. I have edited. Thank you for your input!Wharf
npmjs.com/package/graphql-parser ?Palua
@GabrielBleu from what I understand of the docs, that package generates queries from objects not object from queries.Wharf
It parses the query string and returns an object, but npmjs.com/package/graphql-tag seems way more popular.Palua
@GabrielBleu From the docs of that package: 'That's where this package comes in - it lets you write your queries with ES2015 template literals and compile them into an AST with the gql tag.' I can't find which functionality gets me an object, am I missing something?Wharf
I was thinking something like : const query = gql`${body.query}`Palua
@GabrielBleu ahhhh ok, I'll go give it a spin locally and report back!Wharf
P
39

You can use graphql-tag :

const gql = require('graphql-tag');

const query = `
  {
    qQueryEndpoint {
      id
    }
  }
`;

const obj = gql`
  ${query}
`;

console.log('operation', obj.definitions[0].operation);
console.log('name', obj.definitions[0].selectionSet.selections[0].name.value);

Prints out :

operation query
name qQueryEndpoint

And with your mutation :

operation mutation
name saveSomething
Palua answered 1/3, 2018 at 11:14 Comment(1)
Do we have someting similar for golang ?Squadron
E
29

graphql-tag is built upon the core graphql library (and thus installs it along) - if you just want to get the type of operation and the name of it you can do so, by using graphql directly and analyze the full AST of the parsed GraphQL operation:

const { parse } = require('graphql');

const query = `
{
  qQueryEndpoint {
    id
  }
} 
`;

const mutation = `
mutation {
  saveSomething {
    id
  }
}
`;
const firstOperationDefinition = (ast) => ast.definitions[0];
const firstFieldValueNameFromOperation = (operationDefinition) =>  operationDefinition.selectionSet.selections[0].name.value;

const parsedQuery = parse(query);
const parsedMutation = parse(mutation);

console.log('operation', firstOperationDefinition(parsedQuery).operation);
console.log('firstFieldName', firstFieldValueNameFromOperation(firstOperationDefinition(parsedQuery)));

console.log('operation', firstOperationDefinition(parsedMutation).operation);
console.log('firstFieldName', firstFieldValueNameFromOperation(firstOperationDefinition(parsedMutation)));

That way you do not need to depend on graphql-tag and you can use, the real GraphQL AST (and thus easily adapt to further requirements) - because graphql-tag does not provide the full AST.

See the AST for the query in AST Explorer.

Esch answered 26/11, 2019 at 16:24 Comment(0)
T
3

You could use graphql-js like so:

const { parse, visit } = require('graphql');

const query = `
  {
    books {
      ...rest of the query
    }
  }
`

const ast = parse(query);

const newAst = visit(ast, {
  enter(node, key, parent, path, ancestors) {
    // do some work
  },
  leave(node, key, parent, path, ancestors) {
    // do some more work
  }
});

I belive this is what graphql server implementations uses under the hood, I could be mistaken though.

Templet answered 18/4, 2020 at 12:18 Comment(0)
P
0

You can use graphql-tag.

const gql = require('graphql-tag');

const query = `
  {
    qQueryEndpoint {
      id
    }
  }
`;

const obj = gql`
  ${query}
`;

console.log('operation', obj.definitions[0].operation);
console.log('operationName', obj.definitions[0].name.value);
Pitarys answered 15/9, 2022 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.