Skip to content

Interoperability with other Python GraphQL libraries #34

@miracle2k

Description

@miracle2k

I have a fairly large GraphQL API written in graphene. I am interested in moving to ariadne, but I'd rather not migrate the whole thing in one go. So, since both are based on graphql-core (more or less, the @2 vs @3 thing is a bit of a pain, but solvable), and both ultimately generate a graphql-core schema, I wondered, why not write some schema types in ariadne, while keeping the rest in graphene for now? This allows a step-by-step migration.

It turns out this is pretty easy from the Graphene side:

class External():
    def __init__(self, type):
        super(External, self).__init__()
        self._type = type

class BetterGraphene(GrapheneGraphQLSchema):

    def __init__(
        self,        
        external_types=None,
        **kwargs
    ):
        self.external_types = external_types
        GrapheneGraphQLSchema.__init__(self, **kwargs)

    def type_map_reducer(self, map_, type_):
        if isinstance(type_, External):
            type_ = self.external_types[type_._type]
        return super().type_map_reducer(map_, type_)

    def get_field_type(self, map_, type_):
        if isinstance(type_, External):
            return self.external_types[type_._type]
        return super().get_field_type(map_, type_)

Now I can do:

class Foo(graphene.ObjectType):
    bar = Field(External("Bar"))

And I can create the Bar type however I want, and pass it to the graphene Schema() constructor. For example, I can create a schema with ariadne with make_executable_schema, and take the Bar type from the result.

This actually works!

The problem is that I can't link back. That is, if Bar (no defined with Ariadne) wants to refer to a type that is still in Graphene. Or, simple custom scalars like a DateTime - I can't have them defined in Graphene, and use them from an Ariadne type, and of course, they can't be defined twice.

Ordinarily I would say that I maybe I am just asking for too much: Making those two libraries interact. But as you can see by how little code is required on the Graphene side, this is actually pretty straightforward and without much complexity. Again, this is because the way graphql-core functions: It does the hard lifting, and we are just syntactic sugar on top.

And Graphene makes it super easy to change the mechanism of how the graphql-core schema is generated, by allowing a subclass to override methods.

In Ariadne, make_executable_schema is a bit of a blackbox. What would be needed to make this work is just a little room in make_executable_schema to allow to inject custom types; maybe allowing a custom resolve_type function to be passed through to the ASTDefinitionBuilder.

What are your thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions