'Returning data from apollo-server based on a filter for a nested field
Is it possible to return data for a query in apollo that is based on a filter for a nested field? For example:
Query:
Users($filter: String!) {
user(filter: $filter) {
id,
name,
address(filter: $filter) {
street,
city,
country
}
}
}
TypeDefs:
Query: {
users(filter: String): [User]!
}
User: {
id: ID!,
name: String!,
address: Address
}
Address: {
street: String!,
city: String!,
country: String!
}
Apollo resolvers:
const resolverMap = {
Query: {
User(obj, args, context, info) {
// query api for User info (not including address)
// the final results of the query should only return users with the
// specific address (for example if the filter is country: England, only
// return users that live in England.
},
},
Address: {
address: (obj, args, context, info) {
// query another api for address based on parent (User) Id
},
},
}
Using that query, I only want results returned for users that reside in a specific country, say England. Since this filter is for a nested type [address], would it be possible using this query and not having to query address's first?
Solution 1:[1]
The short answer is no.
Filtering users is the user query's responsibility, not the children's. You are trying to split a query that's actually a single query (filter users by address).
If you want to modify the result of the user query itself, you should add an address parameter to the user query itself so it can filter the users by address.
Something like this:
Users($filter: String!) {
user(filter: $filter, addressFilter: $addressFilter) {
id,
name,
address {
street,
city,
country
}
}
}
Then the resolver look like this:
const resolverMap = {
Query: {
User(obj, args, context, info) {
// query both API for User info (not including address)
// and API for user addresses using $filter and $addressFilter
// Then match results from both API and discard users with invalid
// addresses
// For example if the filter is country: England, only
// return users that live in England with their address
},
},
Address: {
address: (obj, args, context, info) {
// you don't need this resolver unless you want to somehow
// change or format the addresses previously returned
},
},
}
If you still want to make it work the way you initially intended, you may find a way to hack it and make it work. You may be able to access the entire query object from the user resolver parameters, maybe inject stuff in the context to make it available in the resolvers, but even if you manage to do it you are kind of breaking the GraphQL semantics.
The user query is the one responsible for returning the list of users. After it returns the children resolvers can't change the user list itself again, only the children objects.
The address resolver will be called once for each user after the user query has already completed but it has nothing to do with modifying the result of the user query. The address resolver should only change address itself, but not the parent. address is a not a list, so it doesn't make sense to use it for filtering it, but you could use the address resolver to format each address in a particular way.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jens |
