Experience GraphQL Summit 2024: Watch On-demand →
Experience GraphQL Summit 2024: over 45+ technical sessions, real-world success stories, next-gen product demos and more. Watch On-demand →
Using object types, fields, and the all-important Query
type, we can define how we ask a GraphQL service for data and what's available to ask for. But we don't start to see the graph in GraphQL until we can model and traverse the relationships between our types. In the section ahead, we'll look at how to represent the connections between our object types and query them altogether.
In addition to returning scalar type data, fields on an object type can return information about another object type.
Consider the two types defined below.
type Fruit {id: ID!name: String!quantity: Int!price: Int!averageWeight: FloathasEdibleSeeds: Booleannutrients: [String]}type Stall {id: ID!name: String!stallNumber: String!}
We have a Fruit
type, which defines properties that can be applied broadly to many different kinds of fruit. Additionally, we have a Stall
type, which we can query for details about the different food and produce stalls running in a farmer's market, like their names and location number.
When thinking about a particular stall, we might ask what kinds of fruit it sells. And alternatively, when considering a particular type of fruit, we might want to know which stall is selling it. We can traverse, or move across, the relationship between these two types to find out more information: we can go from fruit, to the stall that sells it, to other fruits available at the same stall.
When an object type includes a field that returns another object type, we can think of this like a point of entry to the second object type's fields. When types are linked in this way, we can use the connecting field like a portal: we can jump between types, gathering the information we need in one bundle, and returning home from our journey with all of it in-hand.
This is the power of the graph at work, which results from building your web of data with GraphQL: types that represent their relationships to one another in this way allow us to build more and more complex queries to drill deeper into data and discover new insights.
Let's see how we can model this relationship in GraphQL.
type Fruit {id: ID!name: String!quantity: Int!price: Int!averageWeight: FloathasEdibleSeeds: Booleannutrients: [String]vendor: Stall}type Stall {id: ID!name: String!stallNumber: String!availableFruits: [Fruit!]!}
Notice that in this example, each kind of Fruit
has a single vendor
, which is the field that holds information about the specific Stall
that sells the fruit. (It might be possible for a kind of fruit to exist in the database even without a farmer who is currently selling it, which is why the value is nullable!)
We'll see something different on the Stall
type. Each stall is given a field called availableFruits
, which returns a list of the many different kinds of fruit it sells. Notice that in this case, we expect the availableFruits
field to hand back either an empty list, or a list containing actual Fruit
items. (The list itself cannot be null
, and if it contains items, those items cannot be null
.)
The Query
type is like the springboard that gets us into the graph, where we can jump from one object type's fields to another and build complex queries that give us exactly the data we're looking for. Right now, fruits
is the only way that we can enter the graph and begin querying for data.
type Query {fruits: [Fruit!]!}
When we build a query from the root Query
type, we start by selecting one of its fields. If this field returns an object type—like fruits
returning a list of Fruit
—we need to make at least one selection from that object type's subfields. Let's see an example of this in the next section. To illustrate this, consider the Fruit
and Stall
types below.
type Query {fruits: [Fruit!]!}type Fruit {id: ID!name: String!quantity: Int!price: Int!averageWeight: FloathasEdibleSeeds: Booleannutrients: [String]vendor: Stall}type Stall {id: ID!name: String!stallNumber: String!availableFruits: [Fruit!]!}
All queries start with the available fields on the Query
type. Currently fruits
is our only entry point—the only door we can enter through to get some data—and we expect a list of Fruit
from it. Because we've now jumped to another object type, Fruit
, we need to select at least one of its fields to return in our query.
query GetAllFruit {fruits {}}
Note: The query syntax shown above begins with the
query
keyword and is followed by a descriptive operation name. Within the first set of curly braces we can define the field on theQuery
type that gives us access to specific data within our graph.
Try building this query in the embedded Apollo Sandbox below. Starting with the root Query
type, build a pathway to get the name
, price
, and quantity
of all available fruit. Want a challenge? See if you can pull the name
and stallNumber
for each fruit's vendor
field!
See the solution!
query GetFruits {fruits {namepricequantityvendor {namestallNumber}}}
About
GraphQL.com is maintained by the Apollo team. Our goal is to give developers and technical leaders the tools they need to understand and adopt GraphQL.
GraphQL.com 2024