11 What Is a GraphQL Schema? Concepts and Components
11 What Is a GraphQL Schema? Concepts and Components
GraphQL has transformed the way we build APIs. It not only provides a new way to query data, but also offers a level of flexibility that is hard to achieve with a typical REST API. Behind GraphQL’s power lies an essential element that forms its foundation: the schema. In this article, I’ll take a deep dive into what a GraphQL schema is, the core concepts that underpin it, and the main components every engineer needs to understand in order to build reliable systems with GraphQL.
1. Introduction to the GraphQL Schema
Put simply, a GraphQL schema is a contract between the server and the client. It describes the entire capability of the API - which data types can be queried, the relationships between data, which operations can be executed, and what shape the results take.
Imagine that when building a REST API, you have to document every endpoint, parameter, and response. In GraphQL, all of those details are captured in a single schema that is always up to date and automatically valid.
2. Why Does the Schema Matter?
- Automated Documentation: The schema can be documented and inspected automatically, for example through tools like GraphQL Playground or GraphiQL.
- Data Validation: Any request (query/mutation) that doesn’t conform to the schema is rejected by the server.
- Introspection: Clients can explore the schema to discover the available data types and operations.
3. Basic Schema Structure
A GraphQL schema is written in the Schema Definition Language (SDL), whose form resembles type definitions in TypeScript or other modern programming languages.
A Simple Schema Example
1type Query {
2 user(id: ID!): User
3}
4
5type User {
6 id: ID!
7 name: String!
8 email: String
9}Here, the schema defines a single query (user) that accepts an id of type ID! (required) and returns a User type.
4. Schema Workflow Diagram
Let’s visualize how the schema processes a query using a mermaid diagram:
graph TD
A[Client Kirim Query] --> B[Validasi Terhadap Skema]
B -- Valid --> C[Eksekusi Resolver]
B -- Tidak Valid --> D[Return Error]
C --> E[Return Data]
D --> F[Selesai]
E --> F
5. The Main Components of a GraphQL Schema
- Type (Data Type)
- Query
- Mutation
- Subscription
- Input Type
- Enum
- Interface
- Union
- Scalar
- Directive
- Resolver
We’ll go through them one by one.
6. Type: Building the Data Structure
Every piece of data in GraphQL is defined as a type. A type can be an object, scalar, enum, or a composite of these.
1type Book {
2 id: ID!
3 title: String!
4 author: Author!
5}7. Query: The Gateway to Fetching Data
All data retrieval in GraphQL happens through a Query.
1type Query {
2 books: [Book]
3 book(id: ID!): Book
4}8. Mutation: Manipulating Data
To create, update, or delete data, use a Mutation.
1type Mutation {
2 addBook(title: String!, authorId: ID!): Book!
3 deleteBook(id: ID!): Boolean!
4}9. Subscription: Real-Time Data
A Subscription lets clients receive data changes in real time over WebSocket or another transport.
1type Subscription {
2 bookAdded: Book
3}10. Scalar, Enum, and Input Type
Scalar
Primitive base types such as Int, Float, String, Boolean, and ID.
Enum
Used for a limited set of values.
1enum BookStatus {
2 AVAILABLE
3 CHECKED_OUT
4 LOST
5}Input Type
Used to make input more structured.
1input AddBookInput {
2 title: String!
3 authorId: ID!
4}
1input AddBookInput {
2 title: String!
3 authorId: ID!
4}11. Interface and Union: Polymorphism the GraphQL Way
Interface
A contract definition shared by several types.
1interface Character {
2 id: ID!
3 name: String!
4}
5type Human implements Character {
6 id: ID!
7 name: String!
8 homePlanet: String
9}
10type Droid implements Character {
11 id: ID!
12 name: String!
13 primaryFunction: String
14}Union
For a field whose result may be more than one type.
1union SearchResult = Book | Author12. Resolver: Implementing Business Logic
Every field in a Query, Mutation, or Subscription must have a resolver, whose job is to execute the request.
1const resolvers = {
2 Query: {
3 books: () => getBooksFromDB(),
4 book: (_, { id }) => getBookById(id),
5 },
6 Mutation: {
7 addBook: (_, { title, authorId }) => insertBook(title, authorId),
8 }
9};13. Directive: Customization at the Schema Level
A directive is an annotation on the schema used to modify behavior, such as @deprecated, or you can create your own directive like @auth.
1type Book {
2 title: String!
3 published: Boolean! @deprecated(reason: "Field diganti dengan publishDate")
4}14. The Schema as the Source of Truth
Keep in mind that the GraphQL schema is the center of all API interactions. Changes to the schema (for example, adding a new field or changing a type) immediately affect the entire application ecosystem.
15. Query & Response Simulation
To make things clearer, here is a simulation of a query and its response based on the schema above.
Query:
1query {
2 books {
3 id
4 title
5 author {
6 name
7 }
8 }
9}Response: 1{
2 "data": {
3 "books": [
4 {
5 "id": "1",
6 "title": "GraphQL in Action",
7 "author": { "name": "John Doe" }
8 },
9 {
10 "id": "2",
11 "title": "Learning GraphQL",
12 "author": { "name": "Jane Doe" }
13 }
14 ]
15 }
16}
1{
2 "data": {
3 "books": [
4 {
5 "id": "1",
6 "title": "GraphQL in Action",
7 "author": { "name": "John Doe" }
8 },
9 {
10 "id": "2",
11 "title": "Learning GraphQL",
12 "author": { "name": "Jane Doe" }
13 }
14 ]
15 }
16}16. Schema Component Comparison Table
| Component | Function | Example Syntax |
|---|---|---|
| Type | Primary data structure | type Book { id: ID!... } |
| Query | Data retrieval | type Query { book(id:ID!):Book } |
| Mutation | Data manipulation | type Mutation { addBook... } |
| Subscription | Real-time data | type Subscription { bookAdded... } |
| Enum | Fixed list of values | enum BookStatus { ... } |
| Input | Structured input | input AddBookInput { ... } |
| Interface | Contract for types | interface Character { ... } |
| Union | Multi-type result | `union SearchResult = Book |
| Scalar | Base data types | String, Int, Float... |
| Directive | Schema behavior modifier | @deprecated |
17. Conclusion
Understanding the GraphQL schema is the most fundamental step in building a GraphQL-based API. The schema doesn’t just describe data; it also dictates how the client and server should interact. With a solid grasp of the schema’s concepts and components, you can design APIs that are scalable, robust, and easy to evolve.
As an engineer, don’t hesitate to explore the schema by experimenting with it, inspecting it, and taking advantage of the auto-documentation available across many GraphQL ecosystems. Always remember: The schema is a contract. Make sure it’s clear, strict, and always remains the source of truth in your project.
Cheers,
An engineer who always learns from the schema.