diff --git a/docs/developers/talawa-api/pagination.md b/docs/developers/talawa-api/pagination.md index 722061ed398..c999714e471 100644 --- a/docs/developers/talawa-api/pagination.md +++ b/docs/developers/talawa-api/pagination.md @@ -1,4 +1,4 @@ -# GraphQL connections +# Pagination using graphQL connections:- Connections in graphQL are an approach to pagination popularized by relay client, the graphQL library developed by meta for managing graphQL state on the client applications and its server specification for designing graphQL schema. Though this specification specifically caters towards relay because the library is opinionated about certain patterns for data fetching with graphQL, these schema design principles are not limited to relay and are actually quite ingenious such that they became kind of a best pratice in graphQL ecosystem for implementing a performant pagination system. Here are some resources to learn more about relay style graphQL connections:- @@ -28,13 +28,13 @@ Since there are no community standards for filtering or sorting on graphQL conne The `where` and `sortedBy` arguments should have strictly defined graphQL schema types that pertain to filtering and sorting logic allowed on the connection they exist on. -The `where` field should be a graphQL `input` that should be named using syntax `WhereInput`. So, for `User.posts` it will be named `UserPostsWhereInput` and for `Query.posts` it will be named `QueryPostsWhereInput`. Each field you want to allow filtering on should be defined in this input type. Each field should be a graphQL `input` that specifies all filter actions allowed for that field. If we want to allow filtering on fields that exist on a nested structure within the connection's domain model, then we follow the previous approach recursively for all such fields. +The `where` field should be a graphQL input that should be named using syntax `WhereInput`. So, for `User.posts` it will be named `UserPostsWhereInput` and for `Query.posts` it will be named `QueryPostsWhereInput`. Each field you want to allow filtering on should be defined in this input type. Each field should be a graphQL input that specifies all filter actions allowed for that field. If we want to allow filtering on fields that exist on a nested structure within the connection's domain model, then we follow the previous approach recursively for all such fields. -The `sortedBy` field should be graphQL `input` that should be named using syntax `SortedByInput`. So, for `User.posts` it will be named `UserPostsSortedByInput` and for `Query.posts` it will be named `QueryPostsSortedByInput`. Since, it doesn't make sense to allow sorting on more than one field in one request, each of these inputs should be annotated with graphQL's `oneOf` directive so that only one of the sort fields could be used at any time. Each field we want to allow sorting on should be defined in this input type. Each field should be the graphQL `enum` `SortedByOrder` that specifies the sort order for that field. If we want to allow filtering on fields that exist on a nested structure within the connection's domain model, then we follow the previous approach recursively for all such fields. +The `sortedBy` field should be graphQL input that should be named using syntax `SortedByInput`. So, for `User.posts` it will be named `UserPostsSortedByInput` and for `Query.posts` it will be named `QueryPostsSortedByInput`. Since, it doesn't make sense to allow sorting on more than one field in one request, each of these inputs should be annotated with graphQL's `oneOf` directive so that only one of the sort fields could be used at any time. Each field we want to allow sorting on should be defined in this input type. Each field should be the graphQL enum `SortedByOrder` that specifies the sort order for that field. If we want to allow filtering on fields that exist on a nested structure within the connection's domain model, then we follow the previous approach recursively for all such fields. Naming conventions for fields within the `where` and `sortedBy` arguments can be understood by taking a look at the following schema implementations below:- -## Filtering and sorting on non root `Query` field connections:- +## Filtering and sorting on non root Query field connections:- Let's say we want to provide the capability of filtering the posts of a user by the body and the capability of sorting the posts of a user by the username of the creator of the post. Here's how the graphQL schema for implementing this filter would look like:- @@ -44,11 +44,11 @@ enum SortedByOrder {   DESCENDING } -input PostCreatorSortedByInput { +input PostCreatorSortedByInput @oneOf {   id: SortedByOrder } -input UserPostsSortedByInput { +input UserPostsSortedByInput @oneOf {   body: SortedByOrder   creator: PostCreatorSortedByInput } @@ -104,13 +104,11 @@ type User { } ``` -We expose the argument `where` which is a graphQL input `UserPostsWhereInput` containing a single field named `body` which is a graphQL input `PostWhereBodyInput` containing all the possible filters that can be applied on the body of a post. These filters are just examples, the developers are free to implement additional filters on a field or introduce additional fields to filter upon that might or might not exist on the domain model that the connection represents. For example exposing a filter on `post.creator.username` field which is a nested field that doesn't exist on the `post` domain model itself but can be used to filter the connection `User.posts`. +We expose the argument `where` which is a graphQL input `UserPostsWhereInput` containing two fields named `body` which is a graphQL input `PostWhereBodyInput` containing all the possible filters that can be applied on the body of a post and `creator` which is a graphQL input `PostCreatorWhereInput` for applying recursive filtering on the nested structure `creator` of a `post`. It contains one field named `id` which is a graphQL input `CreatorIdWhereInput` containing all the possible filters that can be applied on the id of a user. -We expose the argument `sortedBy` which is a graphQL input `UserPostsSortedByInput` containing the only two fields that are allowed in any `sortedBy` argument of a connection namely the `field` which is a graphQL `enum` `UserPostsSortedByField` containing two variants named `body` and `creator_username +We expose the argument `sortedBy` which is a graphQL input `UserPostsSortedByInput` containing two fields named `body` which is a graphQL enum `SortedByOrder` and `creator` which is a graphQL input `PostCreatorSortedByInput` for applying recursive sorting on the nested structure `creator` of a `post`. It contains one field named `id` which is a graphQL enum `SortedByOrder`. The graphQL enum `SortedByOrder` contains two variants `ASCENDING` and `DESCENDING` which are the only two possible values to sort any field by. -Variant `body` is used when the connection has to be sorted by body of the post and variant `creator_username` is used when the connection has to be sorted by username of the creator of the post. Usually the `field` enum would contain names of fields that exist on the domain model that the connection represents(like variant `body` here) though in some scenarios we'd want to allow sorting on even more nested fields that don't exist on the domain model that the connection represents(like variant `creator_username` here. - -## Filtering and sorting on root `Query` field connections +## Filtering and sorting on root Query field connections:- Like we previously said, connections on the root `Query` field without any filters are mostly useless by themselves. When a connection like `PostsConnection` exists on a domain model like `User` the filter `post.creator.id` is already applied on it by the virtue of hierarchical relationships in graphQL. This isn't the case for root **Query** field connection resolvers. Here we'll have to provide explicit filters to the connection to enable the clients to query for meaningful posts. @@ -122,11 +120,11 @@ enum SortedByOrder {   DESCENDING } -input PostCreatorSortedByInput { +input PostCreatorSortedByInput @oneOf {   id: SortedByOrder } -input QueryPostsSortedByInput { +input QueryPostsSortedByInput @oneOf {   body: SortedByOrder   creator: PostCreatorSortedByInput } @@ -182,11 +180,9 @@ type Query { } ``` -We define a type `QueryPostsWhere`which contains the fields on the post that we allow filtering on. Here it contains two fields named `body` which is of type `PostWhereBodyInput` and `creator` which is of type `PostCreatorWhereInput`. The type `PostWhereBodyInput` contains all the possible filters that can be applied on the body of the posts for the connection. The type `PostCreatorWhereInput` contains one field named `id` which is of type `UserIdWhere`. The type `UserIdWhere` contains all the possible filters that can be applied on the `id` of the creator of the posts for the connection. - Please don't refrain from using verbose naming in the schema. Try as much as possible to convey the intention using proper data structures and naming while also making sure there are no naming collisions. -These implementations conveys a sane flow of operations to the developer while also sounding like a natural coherent sentence. Take a read:- +These connection arguments convey a sane flow of operations to the developer while also sounding like a natural coherent sentence. Take a read:- _**posts field connection on User type(non root Query connection field):-**_