Open miracle2k opened 4 years ago
I was thinking about allowing GraphQLTypes to be passed as type defs to make_executable_schema
. This would allow you to extract a type defined in one framework and use it in another, it would also allow code-first approach to be mixed with schema-first (which may be useful if parts of your schema come from an introspection protocol rather than from a file on disk).
Playing with this some more. Another option might be allowing the user to pass in a custom
graphql_core.GraphQLSchema
subclass. This would allow this kind of customization in a very similar way to I was doing for graphene above, and, I am sure, would come in handy as an escape hatch in all kinds of cases.
This might be more difficult than I thought. Not looking closely enough before, I failed to realize that most of the code, such as build_ast_schema
is actually part of graphql-core
, not Ariadne. I don't think there is the option of adding features to graphql-core, since they are a 1:1 part of graphql.js
. And graphql.js
apparently intends the buildASTSchema
function to be a way to parse a fully complete schema.
So given these limitations, I can't see how make_executable_schema()
in Ariadne can ever parse an incomplete schema definition, as long as it builds on top of build_ast_schema
. Curious of @patrys had a particular solution in mind to support passing custom GraphQLTypes.
I am not a fan of shoving this logic into the make_executable_schema
. Introducing separate utils providing inter-op would be much preferable here.
I think that simplest (even if not top-performing) approach to your problem would be to use some utility that renders SDL for Graphene type, and use that SDL as intermediate for combining your Graphene types with Ariadne ones. One could pair this with util that converts Graphene's types to Ariadne's bindables:
from ariadne import gql, make_executable_schema
from ariadne_graphene import make_graphene_schema_bindable
from graphene import print_schema
from mygraphene_api import graphene_schema
type_defs = gql("""
type Bar {
name: String
}
""")
schema = make_executable_schema(
[print_schema(graphene_schema), type_defs],
make_graphene_schema_bindable(graphene_schema)
)
However, migrating any larger API from Graphene to Ariadne appears to me as something that should be a process with list of steps one should take and a set of code utilities enabling developers to complete those steps before moving on to next one. Something like this propably:
@rafalp Thanks for that idea. I can see that this is a way to do it, though I'm not quite sold on it's simplicity. In the meantime I did figure out a way to patch the schema returned by Ariadne to refer to the Graphene object types where appropriate, and using directives:
type_defs = gql("""
scalar External;
directive name on FIELD_DEFINITION;
type Bar {
foo: External @name("GrapheneFoo")
}
""")
But implementing this turned out to be quite a bit of effort as well, so I'm not sure if the SDL-generating approach would have been more straightforward.
It still seems to me that there is a potential here - since all GraphQL libraries in Python just generate graphql-core objects, they should be able to interoperate nicely. But at this point I feel I am in over my head, and having solved my own problem, I'll let others decide if there is something actionable here.
make_graphene_schema_bindable
hi @rafalp! Could you provide approximate realization of make_graphene_schema_bindable
from your response?
@Sergei-Rudenkov this is not possible currently. Ariadne is using graphql-core v3 while Graphene is still on v2, and both of those versions share same namespace.
@rafalp I use graphene==3.0.0b6 that use graphql-core v3 under the hood. So I basically have the same question as initial. How to start migration having some api using graphene and some api start using ariadne?
@Sergei-Rudenkov Sorry but no. I'm not able to put time now to dive into Graphene internals to develop thing like that.
I have an idea for changes to make_executable_schema
that Ariadne GraphQL Modules implements that would make Graphene's v3 types work. There would be either a mixin or pass-through function that would make Graphene's type Ariadne-compatible.
Next Ariadne GraphQL Modules is designed to support multiple approaches (APIs? frontends?) to type definition to solve this issue. But we would still need a Graphene-like API for types definitions to take care of this.
I have a fairly large GraphQL API written in
graphene
. I am interested in moving toariadne
, 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:
Now I can do:
And I can create the
Bar
type however I want, and pass it to the grapheneSchema()
constructor. For example, I can create a schema with ariadne withmake_executable_schema
, and take theBar
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 aDateTime
- 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 inmake_executable_schema
to allow to inject custom types; maybe allowing a customresolve_type
function to be passed through to theASTDefinitionBuilder
.What are your thoughts?