Reputation: 93
Given I have a schema that has types: User, Comment, Post, Image; Is it possible to determine the GraphQL types being used in a query, given the query and schema? e.g. if a client had a query
{
user(userName: "username") {
email
comments
}
}
In this case, the query has types User and Comment. Is it possible to determine the programmatically using either the graphql-js or graphql packages for node.js?
Upvotes: 2
Views: 2905
Reputation: 93
For anyone else who runs into this, I found the answer in visit and TypeInfo Here's a function that takes the GraphQL query (document) and a schema and returns which data types from the schema are being used.
import { visit } from 'graphql/language/visitor'
import { parse } from 'graphql/language'
import { TypeInfo, visitWithTypeInfo } from 'graphql'
import { schema as _schema } from '../src/schema/schema'
const getQueryTypes = (schema, query) => {
const typeInfo = new TypeInfo(schema)
var typesMap = {}
var visitor = {
enter(node) {
typeInfo.enter(node)
typesMap[typeInfo.getType()] = true
},
leave(node) {
typesMap[typeInfo.getType()] = true
typeInfo.leave(node)
}
}
visit(parse(query), visitWithTypeInfo(typeInfo, visitor))
return Object.keys(typesMap)
}
const _query = `
query {
...
}
`
console.log(getQueryTypes(_schema, _query))
Upvotes: 7
Reputation: 84687
Given a valid document string representing some GraphQL operation, you can parse the string into an AST.
import { parse, validate } from 'graphql'
const document = parse(someDocumentString)
// if you want to validate your document to verify it matches your schema
const errors = validate(schema, document)
AFAIK, there's no utility function for getting an array of the types in a document, if that's what you're asking for, but you can just traverse the AST and gather whatever information from it. As an example, here's how GraphiQL does just that to generate a map of variables to their corresponding types:
import { typeFromAST } from 'graphql'
export function collectVariables(schema, documentAST) {
const variableToType = Object.create(null);
documentAST.definitions.forEach(definition => {
if (definition.kind === 'OperationDefinition') {
const variableDefinitions = definition.variableDefinitions;
if (variableDefinitions) {
variableDefinitions.forEach(({ variable, type }) => {
const inputType = typeFromAST(schema, type);
if (inputType) {
variableToType[variable.name.value] = inputType;
}
});
}
}
});
return variableToType;
}
Upvotes: 0
Reputation: 820
You have to create types using GraphQLObjectType
, for example:
export default new GraphQLObjectType(
({
name: 'User',
description: 'Represents a User',
fields: () => ({
_id: {
type: GraphQLNonNull(GraphQLString),
resolve: user => user._id,
},
name: {
type: GraphQLNonNull(GraphQLString),
description: 'Name of the user',
resolve: user => user.name,
},
createdAt: {
type: GraphQLString,
description: '',
resolve: user => user.createdAt.toISOString(),
},
updatedAt: {
type: GraphQLString,
description: '',
resolve: user => user.updatedAt.toISOString(),
},
}),
}: GraphQLObjectTypeConfig<User, GraphQLContext>),
);
Then you can use this UserType
on another type, by declaring type: GraphQLNonNull(UserType)
for example.
https://graphql.org/graphql-js/constructing-types/
Hope it helps :)
Upvotes: 0