Graphene: Use Graphene without Relay queries

Created on 25 Aug 2016  路  8Comments  路  Source: graphql-python/graphene

From what I can tell, Graphene does not support non-relay graphql queries (this is with SQLAlchemy).

To be concrete, the following works:
{ allUsers { edges { node { id firstName } } } }

While this
{ allUsers { id firstName } }
Generates this error:
[graphql.error.base.GraphQLError('Cannot query field "id" on type "UserDefaultConnection".')

Did I miss a flag that enables non-relay graphql?

Most helpful comment

@gsvitak Your last example should work replacing the (Folder with FolderModel in the SQLAlchemy query).

class Folder(SQLAlchemyObjectType):
    class Meta:
        model = FolderModel


class Query(graphene.ObjectType):
    folder = graphene.Field(Folder)
    folders = graphene.List(Folder)

    def resolve_folder(self, *args, **kwargs):
        return db.session.query(FolderModel).first()

    def resolve_folders(self, *args, **kwargs):
        return db.session.query(FolderModel).all()

All 8 comments

allUsers is a Connection type so you have to query it via edges and nodes because thats how a Connection is defines.
Connection is GraphQL spec for defining a paginated list - it provides the pageInfo information that lets you paginate a large dataset regardless of wether you're using Relay or not

{ allUsers { id firstName } } is a query you'd do on a List type.
Since allUsers is probably a big table of data that requires pagination its defined as a Connection and not a List

Hey @samvit, using a List for listing items in a collection is also supported.

However if you plan to use pagination in this collection, using a relay ConnectionField should be the path to go, as it provides builtin structures for handling pagination (pageInfo, cursors, ...), cursor based pagination, and so on.

You can still use a List with pagination if you need to, but you would need to implement the pagination for it.

You can achieve it with something similar to this:

class Query(graphene.ObjectType):
    all_users = List(User, page=graphene.Int())

    def resolve_all_users(self, args, context, info):
        page_size = 10
        offset = args.get('page', 0) * page_size

        # The following will only be available in types inheriting from SQLAlchemyObjectType
        user_query = User.get_query(context)

        return user_query.offset(offset).limit(page_size)

Hope this helps!

Thanks for the great work!!

We use Redux instead of Relay in our app. Is there a way to use Graphene with SQLAlchemy without the Relay dependency?

If you mean the React-Relay dependency

The Relay dependency in the client it's not necessary even if you're using the Relay spec in your backend.
So you can use redux (apollo-client) in your client application with Graphene (and graphene relay).

Why is that? Relay is actually two things:

In this sense, Graphene only implements the server specification, so you can use the client you want in the frontend (Relay, apollo-client, ...) without imposing any specific client.

If you mean using a List instead of Relay Connections in the model relations

Yes, there is a way for skipping the Relay Connections conversion!

The SQLAlchemy to graphene types converter checks if the SQLAlchemyObjectType implements the relay.Node type, and in this case it uses a connection whenever a relation to the model defined there is found.

So for skipping this automatic Relay Connection creation, just don't implement the relay.Node in the SQLAlchemyObjectType :).

Thanks for the suggestion. Can you please provide a quick sample?

Do I need to add my own reducers methods.. like the following?

https://github.com/graphql-python/graphene/blob/master/graphene-sqlalchemy/graphene_sqlalchemy/tests/test_query.py

Here is what I am attempting.

schema.py

class Folder(SQLAlchemyObjectType):
    class Meta:
        model = FolderModel

class Query(graphene.ObjectType):
    all_folders = SQLAlchemyConnectionField(Folder)

Schema = graphene.Schema(query=Query, types=[Folder])

also tried

class Folder(SQLAlchemyObjectType):
    class Meta:
        model = FolderModel


class Query(graphene.ObjectType):
    folder = graphene.Field(Folder)
    folders = graphene.List(Folder)

    def resolve_folder(self, *args, **kwargs):
        return db.session.query(Folder).first()

    def resolve_folders(self, *args, **kwargs):
        return db.session.query(Folder)

@gsvitak Your last example should work replacing the (Folder with FolderModel in the SQLAlchemy query).

class Folder(SQLAlchemyObjectType):
    class Meta:
        model = FolderModel


class Query(graphene.ObjectType):
    folder = graphene.Field(Folder)
    folders = graphene.List(Folder)

    def resolve_folder(self, *args, **kwargs):
        return db.session.query(FolderModel).first()

    def resolve_folders(self, *args, **kwargs):
        return db.session.query(FolderModel).all()

thank you!!

Hello,

class Query(graphene.ObjectType):
    product = graphene.Field(Product, id=graphene.ID())
    all_products = relay.ConnectionField(ProductConnection)
    products = graphene.List(Product)
    node = relay.Node.Field()

    def resolve_product(self, args, context, info):
        session =  context['session']
        id_ = from_global_id(args['id'])[1]
        p = session.query(ProductModel).filter(ProductModel.id == id_).first()
        return p

    def resolve_products(self, args, context, info):
        session =  context['session']
        return [x for x in session.query(ProductModel).all()]

    def resolve_all_products(self, args, context, info):
        return []

Is the code above is a good practice?
I have allProducts as a ConnectionField to fullfil Realy requirements and products like a simple list to GraphQL.

Or is it better just to choose one of the implementations?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tricoder42 picture tricoder42  路  4Comments

mraak picture mraak  路  3Comments

lincolnq picture lincolnq  路  3Comments

romaia picture romaia  路  3Comments

nsh87 picture nsh87  路  3Comments