Introduction to Schema
The schema is the heart of any GraphQL API. It's a formal definition of the data that's available and the operations you can perform on it. Think of it as a contract between the client and the server.
Every GraphQL API has a schema. It tells clients what queries they can make, what types of data exist, and how those types relate to each other.
Schema Definition Language
GraphQL has its own language called Schema Definition Language (SDL) for writing schemas. It's a type system that describes your data.
const typeDefs = `
type User {
id: ID!
name: String!
email: String!
age: Int
}
type Query {
user(id: ID!): User
users: [User!]!
}
`;
In this example, we defined a User type with four fields and a Query type that lets us fetch a single user or all users.
Types and Fields
Types are the building blocks of your schema. Each type represents a kind of data, like User, Post, or Product. Fields are the individual pieces of data within a type.
The exclamation mark (!) means the field is required. If a field doesn't have an exclamation mark, it can be null.
type Product {
id: ID! // Required, unique identifier
name: String! // Required string
price: Float! // Required number
description: String // Optional string (can be null)
inStock: Boolean! // Required boolean
}
Notice how we use different scalar types: ID for unique identifiers, String for text, Float for decimal numbers, and Boolean for true/false values.
The Root Types
Every GraphQL schema has three root types that define the entry points for your API:
Query: For reading data. This is the starting point for all read operations.
Mutation: For writing data. Use this when you need to create, update, or delete data.
Subscription: For real-time data. This lets clients receive updates when data changes.
type Query {
user(id: ID!): User
users: [User!]!
}
type Mutation {
createUser(name: String!, email: String!): User!
updateUser(id: ID!, name: String): User!
deleteUser(id: ID!): Boolean!
}
type Subscription {
userCreated: User!
}
Schema Validation
One of the biggest benefits of GraphQL is that the schema is validated at the server level. If a client sends a query that doesn't match the schema, the server rejects it before any resolvers run.
This means you catch errors early. If you try to query a field that doesn't exist, you'll get an error message telling you exactly what's wrong.
// This query will fail because "phone" doesn't exist on User
query {
user(id: "1") {
name
phone // Error: Cannot query field "phone"
}
}