Skip to content

Using Relays in Graphql-core raises a TypeError #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jdcaballerov opened this issue Jun 23, 2023 · 4 comments
Closed

Using Relays in Graphql-core raises a TypeError #205

jdcaballerov opened this issue Jun 23, 2023 · 4 comments

Comments

@jdcaballerov
Copy link

The following code produces a TypeError error

TypeError: Schema must contain uniquely named types but contains multiple types named 'Query'.

import json
from graphql.utilities import build_schema
from graphql.type import GraphQLObjectType, GraphQLSchema

def read_file(file_path, is_json: bool = False):
    file_contents = None
    try:
        with open(file_path, "r") as file:
            file_contents = file.read()
    except FileNotFoundError:
        print(f"File '{file_path}' not found.")
    except IOError:
        print(f"Error reading file '{file_path}'.")

    if not file_contents:
        raise Exception("GraphQL schema is empty")

    return json.loads(file_contents) if is_json else file_contents


schema = build_schema(read_file("schemas/github.graphql"))

GraphQLSchema(GraphQLObjectType('Query', lambda:schema.query_type.fields))

Github's GraphQL public schema includes a relay Query type as follows:

type Query {
  ...

  """
  Workaround for re-exposing the root query object. (Refer to
  https://github.com/facebook/relay/issues/112 for more information.)
  """
  relay: Query!
 ...

}

When using this schema in graphql-core python library I get a type error if I try to rebuild the schema.

TypeError: Schema must contain uniquely named types but contains multiple types named 'Query'.

Is that a bug in graphql-core code or am I missing something? How to properly handle relays ?

@Cito
Copy link
Member

Cito commented Jun 23, 2023

I think the error message is corect. The tree of query_type.fields already includes the Query type, since it is referenced, so you can't define it again. This works, since you're using the same Query type:

GraphQLSchema(schema.get_type('Query'))

You can also remove the reference to the query type and then later add it again:

query = GraphQLObjectType('Query', {
    name: field for name, field in schema.query_type.fields.items()
    if name != 'relay'})
schema = GraphQLSchema(query)
schema.query_type.fields['relay!'] = GraphQLNonNull(query)

But I'm not sure what you actually want to achieve.

@jdcaballerov
Copy link
Author

jdcaballerov commented Jun 26, 2023

@Cito thanks for taking the time to answer. What I want to achieve that took me in this direction is a use case where I need to select, out of a big schema, just some subset of queries and mutations to obtain a smaller "scoped" schema. That's why I add the queries and mutations in that way.

I've been using a solution like the second one you propose, however, this gets complicated in some cases where the query type mentioned is nested. i.e

type Mutation {
 ....
  replaceTimeSeriesRange(
    """
    The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
    """
    input: ReplaceTimeSeriesRangeInput!
  ): ReplaceTimeSeriesRangePayload
....
}

  """All input for the `replaceTimeSeriesRange` mutation."""
input ReplaceTimeSeriesRangeInput {
  """
  An arbitrary string value with no semantic meaning. Will be included in the
  payload verbatim. May be used to track mutations by the client.
  """
  clientMutationId: String
  attributeOrTagId: BigInt
  entries: [TimeSeriesEntryInput]
  startTime: Datetime
  endTime: Datetime
}

"""The output of our `replaceTimeSeriesRange` mutation."""
type ReplaceTimeSeriesRangePayload {
  """
  The exact same `clientMutationId` that was provided in the mutation input,
  unchanged and unused. May be used by a client to track mutations.
  """
  clientMutationId: String
  json: JSON

  """
  Our root query field type. Allows us to run any query from our mutation payload.
  """
  query: Query
}

adding the mutation replaceTimeSeriesRange to a schema will raise the TypeError in a similar way.

@Cito
Copy link
Member

Cito commented Jun 28, 2023

Maybe have a look at the code of utilities.lexicographic_sort_schema and do it similary - instead of sorting fields, you would filter fields.

@jdcaballerov
Copy link
Author

I'll need to check. Thanks for the hint. Closing since it's not a bug of the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants