3. Schema definition language (SDL)
3m

Overview

To begin putting the pieces of our together, we need to take a closer look at Schema Definition Language, or . This is the syntax that lets us actually define and their in a way that the can understand.

In this lesson, we will:

  • Explore syntax
  • Define a basic schema with a Query and a Listing type
  • Add our dependencies

📄 Exploring SDL

You can think of our server's schema as a between the server and any client asking for data. It defines what a API can and can't do, and how clients can request or change data. It's an abstraction layer that provides flexibility to consumers while hiding backend implementation details.

In practice, a schema is a collection of object types that contain fields. Each has a type of its own. A field's type can be scalar (such as an Int or a String), or it can be another object type. We'll see an example of this shortly.

GraphQL type syntax

We declare a type using the type keyword, followed by the name of the type (PascalCase is best practice), then opening brackets to hold its :

Example GraphQL type
type Planet {
}

are declared by their name (camelCase), a colon, and then the type of the field ( or object). A field can also contain a list, indicated by square brackets:

type Planet {
id: ID
name: String
mass: Int
namesOfMoons: [String]
}

Nullability in GraphQL

In addition, we can indicate whether each value is nullable or non-nullable. If a field should never be null, we add an exclamation mark after its type:

type Planet {
id: ID!
name: String!
mass: Int
namesOfMoons: [String]
}

This syntax states that it's not valid for a Planet to return null for the id or name ; we require them to return a value that matches their specified data type. By contrast, we'll permit mass and namesOfMoons to be null if we have no data to return.

Working with multiple object types

also gives us the ability to represent relationships between objects. Take these two for example:

type Planet {
id: ID!
name: String!
mass: Int
}
type Galaxy {
id: ID!
name: String!
yearDiscovered: Int
}

Suppose we want to represent the relationship between planets and galaxies. For example, we might want each planet to indicate the galaxy it belongs to. How do we represent this in ?

In this case, we could update Planet with a that returns another ; one that specifies which galaxy it belongs to.

type Planet {
id: ID!
name: String!
mass: Int
galaxy: Galaxy
}
type Galaxy {
id: ID!
name: String!
yearDiscovered: Int
}

This relationship lets us details about an planet, then query further details about the galaxy it's found in. We can ask more complex questions of our data—like "What's the mass of this planet, and what is the name of the galaxy it belongs to?"—and get all of the answers in one neatly-bundled response.

Documenting the schema

All right, last thing before we start writing our schema: descriptions.

It's good practice to your schema, in the same way that it's helpful to comment your code. It makes it easier for your teammates (and future you) to make sense of what's going on. It also allows tools like the to guide API consumers on what they can achieve with your API right when and where they need it.

To do that, the lets you add descriptions to both types and by writing strings (in quotation marks) directly above them.

"I'm a regular description"

Triple "double quotes" allow you to add line breaks for clearer formatting of lengthier comments.

"""
I'm a block description
with a line break
"""

Here's what a fully-documented type might look like.

"Astronomical information for a single planet."
type Planet {
"The ID for the planet"
id: ID!
"The planet's name"
name: String!
"The total estimated mass of the planet (in kg)"
mass: Int
"The galaxy the planet is located in"
galaxy: Galaxy
}

With that final point covered, let's build our schema!

Practice

Which of the following are valid field types?
What does an exclamation mark after a field's type indicate?
Which of these are always true about the Query type?

Key takeaways

  • The of the Query type are entry points into our schema. These are the top-level that a consumer can for.
  • define we can for data. These fields can return data (such as String or Int) or return other .

Up next

With that final point covered, let's jump into the next lesson and build our schema!

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.