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?
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?
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.
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?
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?
Most helpful comment
@gsvitak Your last example should work replacing the (
FolderwithFolderModelin the SQLAlchemy query).