Skip to content

Document how to implement Connection fields and pagination #887

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
antoine-gallix opened this issue Jan 4, 2019 · 6 comments
Closed

Document how to implement Connection fields and pagination #887

antoine-gallix opened this issue Jan 4, 2019 · 6 comments

Comments

@antoine-gallix
Copy link

From the documentation on relay Connection, there is an example on how to define a connection object type, but in the part that shows how to define a connection field, it's not clear what should the resolver return. The example only show an empty list returned. What type of object is a connection resolver supposed to return? Could you show a concrete example?

Also the sentence in that paragraph is not clear:

You can create connection fields in any Connection, in case any ObjectType that implements Node will have a default Connection.

What does this sentence mean?

@antoine-gallix
Copy link
Author

What I found out:

The following worked to define a List field

class Thing(SQLAlchemyObjectType):
    class Meta:
        model = models.Thing # sqlalchemy model

things = graphene.List(ThingGraphQLType)

@staticmethod
def resolve_things(args, info):
    # returning a query seems to be ok
    return Thing.get_query(info=info)

However the following does not:

class ThingConnection(relay.Connection):
    class Meta:
        node = Thing

things = relay.ConnectionField(ThingConnection)

@staticmethod
def resolve_things(args, info):
    return Thing.get_query(info=info)

graphql.error.located_error.GraphQLLocatedError: object of type 'BaseQuery' has no len()

But this works:

@staticmethod
def resolve_things(args, info):
    return Thing.get_query(info=info).all()

This is all based on try and error. That could be nice to explain that upfront in the doc.

@antoine-gallix
Copy link
Author

After the previous declaration, I see on my schema that ThingConnection exposes first,last,before and after. This makes me think that pagination is implemented.

However if I try to use the first argument in my query, like things(first:1) {edges{node{name}}}, I get back an error like graphql.error.located_error.GraphQLLocatedError: resolve_farm_connection() got an unexpected keyword argument 'first'

Looks like it's not implemented. So I add the first argument to my resolver signature, without actually implementing the pagination:

@staticmethod
resolve_things(args,info,first=None):
    # 'first' argument is not used anywhere, only added to the signature
    return models.Things.query().all()

There is three Things in my db. If I query things {edges{node{name}}}, I get 3 edges. Then if things(first:1) {edges{node{name}}}, I get only one. So after all even if I don't implement it myself, something in the Connection class will do it. But I still need to allow first in the resolver signature.

I keep exploring this package but it's a slow process of try and error to discover features, find out what is possible and how to do it. The documentation is really lacking in this area.

@antoine-gallix antoine-gallix changed the title Document how to implement Connection fields Document how to implement Connection fields and pagination Jan 4, 2019
@louisdvs
Copy link

louisdvs commented Jan 17, 2019

Agree that it's a huge trial and error effort to understand this lib. My understanding is that pagination is implemented on the edges, you appear to be trying to implement it on the root node. ie I think:
things(first:1) {edges{node{name}}}
should be:
things{edges(first:1){node{name}}}
This keeps it clean when you want to filter things, then paginate the results ie:

things(name:$name,type:$type)
      { edges(first:$limit) {
         node{
           name
         }
       }
    }

That is the benefit that you get from having the tedious amount of boilerplate in your queries.

@antoine-gallix
Copy link
Author

Ok I'll start completing the doc as I discover about the package: #892

@stale
Copy link

stale bot commented Jul 29, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jul 29, 2019
@stale stale bot closed this as completed Aug 5, 2019
@jmandt
Copy link

jmandt commented Feb 16, 2021

@antoine-gallix: There is another solution to this problem in which you do not have to add all arguments of the pagination in your staticmethod resolver. Instead of

@staticmethod
resolve_things(args,info,first=None):
    # 'first' argument is not used anywhere, only added to the signature
    return models.Things.query().all()

just do

@staticmethod
resolve_things(args,info, *args, **kwargs):
    # 'first' argument is not used anywhere, only added to the signature
    return models.Things.query().all()

This way all your arguments will be passed to the Connection Type and you don't have to care about it anymore :)

@louisdvs: I think your way of doing the pagination on the edges is not consistent with the relay specification and should not be applied. If people will query the API thinking it is relay conform, they will fail in doing so.

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

No branches or pull requests

4 participants