Example #1
0
    def execute(self, document):
        """
        Queries the schema in python.

        :param document: A GraphQL query string
        :return: JSON of returned data or errors

        e.g.
        ::

            query = '''
            {
                users {
                    name
                }
            }
            '''
            schema.execute(query)

        Might return
        ::

            {
                "data": {
                    "users": [
                        {"name": "Buffy Summers"},
                        {"name": "Willow Rosenberg"},
                        {"name": "Xander Harris"}
                    ]
                }
            }
        """
        parser = GraphQLParser()
        ast = parser.parse(document)

        queries = [
            definition for definition in ast.definitions
            if isinstance(definition, Query)
        ]
        assert len(queries) == 1, "Exactly one query must be defined"

        fragments = {
            definition.name: definition
            for definition in ast.definitions
            if isinstance(definition, FragmentDefinition)
        }

        return {
            'data':
            self.query_root(
                ast=queries[0],
                data=None,
                fragments=fragments,
            ).serialize(),
        }
Example #2
0
def validate_graphql_request(payload: str):
    """Method to parse http request payload verify it is a valid GraphQL query or mutation and return a GraphQL document."""

    try:
        return GraphQLParser().parse(payload)
    except Exception:
        raise RequestException(400, 'Invalid GraphQL payload.')
Example #3
0
class QueryEngine:
    """
    GraphQL query engine.

    Usage:

        graphql = QueryEngine()
        graphql.addModel('user', user)
        result = graphql.query('''
            {
                user(id: 4) {
                    name
                }
            }
        ''')
        # result = {'user': {'name': 'Mark Zuckerberg'}}
    """
    def __init__(self, **kwargs):
        self._models = {}
        self._parser = GraphQLParser()

    def addModel(self, name, model):
        self._models[name] = model

    def _getAST(self, query):
        return self._parser.parse(query)

    def query(self, query):
        ast = self._getAST(query)
Example #4
0
    def execute(self, document):
        """
        Queries the schema in python.

        :param document: A GraphQL query string
        :return: JSON of returned data or errors

        e.g.
        ::

            query = '''
            {
                users {
                    name
                }
            }
            '''
            schema.execute(query)

        Might return
        ::

            {
                "data": {
                    "users": [
                        {"name": "Buffy Summers"},
                        {"name": "Willow Rosenberg"},
                        {"name": "Xander Harris"}
                    ]
                }
            }
        """
        parser = GraphQLParser()
        ast = parser.parse(document)

        query_ast = ast.definitions[0]

        if any(selection.name == '__schema'
               for selection in query_ast.selections):
            raise NotImplementedError(
                'This version of django-graph-api does not support introspection'
            )

        return {
            'data': self.query_root(query_ast, None).serialize(),
        }
Example #5
0
def get_completions(gql, idx, schema):
    """Creates AST from `gql` query string, finds out exactly where cursor is in
    string, and uses `schema` to get appropriate completions. Doesn't protect
    against exceptions. They should be handled by calling code.
    """
    try:  # at module import time this package is not available
        from graphql.parser import GraphQLParser
        from graphql.lexer import GraphQLLexer
    except ImportError:
        raise Exception('Install graphql-py with pip for GraphQL autocomplete')

    try:  # monkey-patch this class, the `t_NULL` method breaks parsing
        delattr(GraphQLLexer, 't_NULL')
    except AttributeError:
        pass

    start, end = slurp_word(gql, idx)
    gql_parser = GraphQLParser()
    ast = gql_parser.parse(gql[:start] + placeholder + gql[end:],
                           lexer=GraphQLLexer())

    for query in ast.definitions:  # get path if it exists
        path = placeholder_path(query, placeholder)
        if path is not None:
            break

    query_type, types = schema
    t = resolve_type(path, types, query_type)
    fields = types[t]['fields']

    completions = []
    for f in fields.values():
        name = f['name']
        args = [a['name'] + ':' for a in f['args']]
        args_string = '({})'.format(', '.join(args)) if args else ''
        type_name = resolve_field_type(f)
        completions.append([
            '{}{}\t{}'.format(name, args_string, type_name),
            '{}{}'.format(name, args_string),
        ])

    return (completions, sublime.INHIBIT_WORD_COMPLETIONS
            | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
    def __init__(self, document, schema, variables=None, operation_name=None):
        """
        Creates a Request object that can be validated and executed.

        :param document: The query string to execute.

            e.g. ``"query episodeNames { episodes { name } }"``

        :param schema: A Schema object to run the query against
        :param variables: A ``dict`` of variables to pass to the query (optional)
        :param operation_name: If the document contains multiple named queries,
            the name of the query to execute (optional)
        """
        self.document = document
        self.variables = variables or {}
        self.operation_name = operation_name
        self.schema = schema
        self._validated = False
        self._errors = []
        self.query_root = None
        parser = GraphQLParser()

        if not self.document:
            self._errors.append(GraphQLError('Must provide query string.'))
        else:
            try:
                self.ast = parser.parse(self.document)
            except (graphql_exceptions.LexerError,
                    graphql_exceptions.SyntaxError) as e:
                self.ast = None
                self._errors.append(
                    GraphQLError(
                        'Parse error: {}'.format(e),
                        line=e.line,
                        column=e.column,
                    ))

        # Additional errors are meaningless if we couldn't parse the document
        if self._errors:
            self._validated = True
Example #7
0
class GraphQLParseTest(TestCase):
    parser = GraphQLParser()

    def test_shorthand(self):
        self.assertEqual(
            self.parser.parse('{ me { name } }'),
            Document(definitions=[
                Query(selections=[
                    Field(selections=[Field(name='name')], name='me')
                ])
            ]))
        self.assertEqual(
            self.parser.parse("""
                {
                  user(id: 4) {
                    id
                    name
                    profilePic
                    avatar: profilePic(width: 30, height: 30)
                  }
                }
            """),
            Document(definitions=[
                Query(selections=[
                    Field(selections=[
                        Field(name='id'),
                        Field(name='name'),
                        Field(name='profilePic'),
                        Field(alias='avatar',
                              name='profilePic',
                              arguments=[
                                  Argument(name='width', value=30),
                                  Argument(name='height', value=30)
                              ])
                    ],
                          name='user',
                          arguments=[Argument(name='id', value=4)])
                ])
            ]))

    def test_mutation_shorthand(self):
        self.assertEqual(
            self.parser.parse("""
                mutation {
                    likeStory(storyID: 12345) {
                        story {
                            likeCount
                        }
                    }
                }
            """),
            Document(definitions=[
                Mutation(selections=[
                    Field(selections=[
                        Field(name='story',
                              selections=[Field(name='likeCount')]),
                    ],
                          name='likeStory',
                          arguments=[Argument(name='storyID', value=12345)])
                ])
            ]))

    def test_with_fragments(self):
        self.assertEqual(
            self.parser.parse("""
                query withNestedFragments {
                  user(id: 4) {
                    friends(first: 10) {
                      ...friendFields
                    }
                    mutualFriends(first: 10) {
                      ...friendFields
                    }
                  }
                }

                fragment friendFields on User {
                  id
                  name
                  ...standardProfilePic
                }

                fragment standardProfilePic on User {
                  profilePic(size: "small")
                }
            """),
            Document(definitions=[
                Query(
                    name='withNestedFragments',
                    selections=[
                        Field(selections=[
                            Field(selections=[
                                FragmentSpread(name='friendFields')
                            ],
                                  name='friends',
                                  arguments=[Argument(name='first', value=10)
                                             ]),
                            Field(selections=[
                                FragmentSpread(name='friendFields')
                            ],
                                  name='mutualFriends',
                                  arguments=[Argument(name='first', value=10)])
                        ],
                              name='user',
                              arguments=[Argument(name='id', value=4)])
                    ]),
                FragmentDefinition(type_condition=NamedType(name='User'),
                                   name='friendFields',
                                   selections=[
                                       Field(name='id'),
                                       Field(name='name'),
                                       FragmentSpread(
                                           name='standardProfilePic')
                                   ]),
                FragmentDefinition(
                    type_condition=NamedType(name='User'),
                    name='standardProfilePic',
                    selections=[
                        Field(name='profilePic',
                              arguments=[Argument(name='size', value='small')])
                    ])
            ]))

    def test_shorthand_query_with_fragments(self):
        self.assertEqual(
            self.parser.parse("""
                {
                  hero {
                    name
                    ...DroidFields
                  }
                }

                fragment DroidFields on Droid {
                  primaryFunction
                }
            """),
            Document(definitions=[
                Query(selections=[
                    Field(name='hero',
                          selections=[
                              Field(name='name'),
                              FragmentSpread(name='DroidFields'),
                          ]),
                ]),
                FragmentDefinition(type_condition=NamedType(name='Droid'),
                                   name='DroidFields',
                                   selections=[Field(name='primaryFunction')]),
            ]))

    def test_shorthand_vs_query(self):
        self.assertEqual(
            self.parser.parse("""
               query {
                  hero {
                    name
                  }
               }
            """),
            self.parser.parse("""
               {
                  hero {
                    name
                  }
               }
            """),
        )

    def test_variables(self):
        self.assertEqual(
            self.parser.parse("""
                query withVariable($userId: Int = 0, $userName: String) {
                  user(id: $userId, name: $userName) {
                    nick
                  }
                }
            """),
            Document(definitions=[
                Query(name='withVariable',
                      variable_definitions=[
                          VariableDefinition(name='userId',
                                             type=NamedType(name='Int'),
                                             default_value=0),
                          VariableDefinition(name='userName',
                                             type=NamedType(name='String'))
                      ],
                      selections=[
                          Field(selections=[Field(name='nick')],
                                name='user',
                                arguments=[
                                    Argument(
                                        name='id',
                                        value=Variable(name='userId'),
                                    ),
                                    Argument(name='name',
                                             value=Variable(name='userName'))
                                ])
                      ])
            ]))

    def test_arguments(self):
        self.assertEqual(
            self.parser.parse("""
                {
                  episodes (number: null, isPrequel: false) {
                    id
                  }
                }
            """),
            Document(definitions=[
                Query(selections=[
                    Field(selections=[Field(name='id')],
                          name='episodes',
                          arguments=[
                              Argument(name='number', value=None),
                              Argument(name='isPrequel', value=False)
                          ])
                ])
            ]))

    def test_with_subscription(self):
        self.assertEqual(
            self.parser.parse("""
                subscription onSomething($deviceId: ID!) {
                    onSomething(deviceId: $deviceId,) {
                        deviceId
                        deviceType
                        datapoints {
                            id
                        }
                    }
                }
            """),
            Document(definitions=[
                Subscription(name="onSomething",
                             selections=[
                                 Field(name="onSomething",
                                       arguments=[
                                           Argument(name="deviceId",
                                                    value=Variable(
                                                        name="deviceId"))
                                       ],
                                       selections=[
                                           Field(name="deviceId"),
                                           Field(name="deviceType"),
                                           Field(name="datapoints",
                                                 selections=[Field(name="id")])
                                       ])
                             ],
                             variable_definitions=[
                                 VariableDefinition(name="deviceId",
                                                    type=NonNullType(
                                                        type=NamedType(
                                                            name="ID")))
                             ])
            ]))
Example #8
0
 def __init__(self, **kwargs):
     self._models = {}
     self._parser = GraphQLParser()
Example #9
0
class GraphQLParseTest(TestCase):
    parser = GraphQLParser()

    def test_shorthand(self):
        self.assertEqual(
            self.parser.parse('{ me { name } }'),
            Document(definitions=[
                Query(selections=[
                    Field(selections=[Field(name='name')], name='me')
                ])
            ]))
        self.assertEqual(
            self.parser.parse("""
                {
                  user(id: 4) {
                    id
                    name
                    profilePic
                    avatar: profilePic(width: 30, height: 30)
                  }
                }
            """),
            Document(definitions=[
                Query(selections=[
                    Field(selections=[
                        Field(name='id'),
                        Field(name='name'),
                        Field(name='profilePic'),
                        Field(alias='avatar',
                              name='profilePic',
                              arguments=[
                                  Argument(name='width', value=30),
                                  Argument(name='height', value=30)
                              ])
                    ],
                          name='user',
                          arguments=[Argument(name='id', value=4)])
                ])
            ]))

    def test_with_fragments(self):
        self.assertEqual(
            self.parser.parse("""
                query withNestedFragments {
                  user(id: 4) {
                    friends(first: 10) {
                      ...friendFields
                    }
                    mutualFriends(first: 10) {
                      ...friendFields
                    }
                  }
                }

                fragment friendFields on User {
                  id
                  name
                  ...standardProfilePic
                }

                fragment standardProfilePic on User {
                  profilePic(size: "small")
                }
            """),
            Document(definitions=[
                Query(
                    name='withNestedFragments',
                    selections=[
                        Field(selections=[
                            Field(selections=[
                                FragmentSpread(name='friendFields')
                            ],
                                  name='friends',
                                  arguments=[Argument(name='first', value=10)
                                             ]),
                            Field(selections=[
                                FragmentSpread(name='friendFields')
                            ],
                                  name='mutualFriends',
                                  arguments=[Argument(name='first', value=10)])
                        ],
                              name='user',
                              arguments=[Argument(name='id', value=4)])
                    ]),
                FragmentDefinition(type_condition=NamedType(name='User'),
                                   name='friendFields',
                                   selections=[
                                       Field(name='id'),
                                       Field(name='name'),
                                       FragmentSpread(
                                           name='standardProfilePic')
                                   ]),
                FragmentDefinition(
                    type_condition=NamedType(name='User'),
                    name='standardProfilePic',
                    selections=[
                        Field(name='profilePic',
                              arguments=[Argument(name='size', value='small')])
                    ])
            ]))

    def test_shorthand_query_with_fragments(self):
        self.assertEqual(
            self.parser.parse("""
                {
                  hero {
                    name
                    ...DroidFields
                  }
                }

                fragment DroidFields on Droid {
                  primaryFunction
                }
            """),
            Document(definitions=[
                Query(selections=[
                    Field(name='hero',
                          selections=[
                              Field(name='name'),
                              FragmentSpread(name='DroidFields'),
                          ]),
                ]),
                FragmentDefinition(type_condition=NamedType(name='Droid'),
                                   name='DroidFields',
                                   selections=[Field(name='primaryFunction')]),
            ]))

    def test_variables(self):
        self.assertEqual(
            self.parser.parse("""
                query withVariable($userId: Int = 0, $userName: String) {
                  user(id: $userId, name: $userName) {
                    nick
                  }
                }
            """),
            Document(definitions=[
                Query(name='withVariable',
                      variable_definitions=[
                          VariableDefinition(name='userId',
                                             type=NamedType(name='Int'),
                                             default_value=0),
                          VariableDefinition(name='userName',
                                             type=NamedType(name='String'))
                      ],
                      selections=[
                          Field(selections=[Field(name='nick')],
                                name='user',
                                arguments=[
                                    Argument(
                                        name='id',
                                        value=Variable(name='userId'),
                                    ),
                                    Argument(name='name',
                                             value=Variable(name='userName'))
                                ])
                      ])
            ]))
def main():

    moreDetails = False

    if len(sys.argv) > 1 and sys.argv[1] == 'True':
        moreDetails = True
        print(
            "You have chosen to get some more details of your schema coverage. This will be provided in a file in root "
            "called 'individualSchemaCoverage.csv'. The overview of the covered schema will be printed to a file "
            "called 'schemaCoverageDictionary.csv'.")
        with open('individualSchemaCoverage.csv', 'w') as csvfile:
            csvwriter = csv.writer(csvfile)
            csvwriter.writerow(['testID', 'individualCoverage'])

    templateLoader = jinja2.FileSystemLoader(searchpath="")
    templateEnv = jinja2.Environment(loader=templateLoader)
    template = templateEnv.get_template(cfg.test_template)

    parser = GraphQLParser()
    encoder = json.JSONEncoder()

    types = requests.post(cfg.graphql_url,
                          data=encoder.encode(cfg.schema_query),
                          headers={'content-type': 'application/json'})

    schema = json.loads(types.content)['data']['__schema']

    #jsonschema = json.dumps(schema)
    #jsonFile = open('schema.json', 'w+')
    #jsonFile.write(jsonschema)

    createDict = CreateDictionaries(schema)
    possValuesDict = createDict.possibleValuesDictionary()
    schemaCoverageDict = createDict.schemaCoverageDictionary()

    searcher = SchemaSearcher(schema, schemaCoverageDict)
    walker = AstWalker(searcher)
    createAssertions = CreateAssertions(possValuesDict)

    for f in os.listdir('queries/'):
        id = f.split('.json')[0]
        if id == '.DS_Store':
            continue
        testName = 'Q' + ''.join(id.split('-')) + 'Test'
        payload = open('queries/' + f).read()
        jsonPayload = "<<<'JSON'\n" + payload + "\nJSON"

        try:
            dict = json.loads(payload)
        except:
            print("Couldn't load " + id)
            continue

        try:
            astree = parser.parse(dict['query'])
        except:
            print('Something is wrong with test ' + id)
            continue

        mutation = False
        query = None

        # Checking there are no mutations in query
        for tree in astree.definitions:
            if type(tree) == graphql.ast.Mutation:
                print(id + ' contains mutations and will not be used')
                mutation = True
                break

        # Skipping current query if contains mutations
        if mutation:
            continue

        searcher.setId(id)

        # Checking other types in query
        for tree in astree.definitions:
            if type(tree) == graphql.ast.FragmentDefinition:
                success = createDict.createFragmentDictionary(tree, walker)
                if success:
                    walker.fragmentDictionary = createDict.fragmentDictionary
                else:
                    astree.definitions.append(tree)
                    continue
            elif type(tree) == graphql.ast.Query or type(tree) == None:
                query = tree

        rootNode = walker.walk(query, None)

        if moreDetails:
            createSchemaDict = CreateDictionaries(schema)
            individualSchemaCoverageDict = createSchemaDict.schemaCoverageDictionary(
            )
            schemaSearcher = SchemaSearcher(schema,
                                            individualSchemaCoverageDict)
            schemaWalker = AstWalker(schemaSearcher)
            schemaWalker.fragmentDictionary = createDict.fragmentDictionary
            schemaWalker.walk(query, None)
            with open('individualSchemaCoverage.csv', 'a') as csvfile:
                csvwriter = csv.writer(csvfile)
                csvwriter.writerow(
                    [id, (schemaSearcher.calculateSchemaCoverage() * 100)])

        variables = ['$a', '$b', '$c', '$d', '$e', '$f', '$g']

        try:
            assertions = []
            for node in rootNode:
                nodeAssertions = createAssertions.createAssertions(
                    node, variables)
                for line in nodeAssertions:
                    assertions.append(line)
            output = template.render(className=testName,
                                     query=jsonPayload,
                                     allAssertions=assertions,
                                     graphQLURL=cfg.graphql_url,
                                     authToken=cfg.authorization_token)
            testfile = open('testCases/' + testName + '.php', 'w')
            testfile.write(output)
            testfile.close()
        except:
            continue

    if moreDetails:
        with open('schemaCoverageDictionary.csv', 'w') as csvfile:
            csvwriter = csv.writer(csvfile)
            csvwriter.writerow(
                ['schemaTuple', 'visited', 'timesVisited', 'id'])
            for line in schemaCoverageDict:
                csvwriter.writerow([
                    line, schemaCoverageDict[line][1],
                    schemaCoverageDict[line][0], schemaCoverageDict[line][2]
                ])

    print("The schema coverage for the generated test suite is: " +
          str(searcher.calculateSchemaCoverage() * 100) + ' %' +
          " where mutations are: " + str(searcher.calculateMutations() * 100) +
          ' % of the schema and input objects are: ' +
          str(searcher.calculateInputTypes() * 100) + ' % of the schema.')
Example #11
0
def get_graphql_tree(content):
    parser = GraphQLParser()
    ast = parser.parse(query)
    return ast.definitions[0].selections[0]