Queries in GraphQL are based on two things: an entry point and traversals. The entry point is the initial object (or objects) that are coming from a Query or a Mutation type. This provides a "foothold" in the objects graph.
Then the query can define what other fields and objects it needs in the response. This makes GraphQL queries powerful: the client can define what it needs and it gets exactly that.
For example, a client might want to show the social graph for a user, so it fetches the friends:
query {
user(id: "user1") {
name
friends {
name
}
}
}
A different client might want to show an admin panel and show all the users with their email addresses and permissions:
query {
allUsers {
name
email
permissions {
name
}
}
}
Both queries above use the same object graph, but they get different data. This gives GraphQL queries a lot of flexibility and if used well provides a faster user experience.
It's all too easy to query everything and then select what is needed on the client-side. But this does not utilize the flexibility of the queries and goes against the best practices for GraphQL.
But queries are a lot more powerful than just selecting what fields the client needs. GraphQL provides a lot of features to fine-tune their behavior. In this chapter we'll look into the most useful ones and how to use them.
What gives the most versatility for GraphQL queries is the ability to select the fields they need in the response. A type might have many fields, but if the client needs just a few of them, then it consumes less resources to omit the unneeded ones.
For example, a User
object has a username
, a bio
, and an email
address:
type User {
username: String!
email: String
bio: String
}
type Query {
user(username: String!): User
}
If the client does not need the email
address, it can choose not to ask for that:
# query
query MyQuery {
user(username: "user1") {
username
bio
}
}
And the result: