GraphQL is a query language for APIs and a runtime for executing queries by using a type system you define for your data. Unlike REST APIs that expose multiple endpoints for different resources, GraphQL provides a single endpoint that can return exactly the data you request.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REST API β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β GET /users/1 β { id: 1, name: "John", email: "..." } β
β GET /users/1/posts β [ { id: 1, title: "...", body: "..." }] β
β GET /posts/1 β { id: 1, title: "...", author_id: 1 } β
β β
β π΄ Problems: β
β β’ Multiple round trips β
β β’ Over-fetching (getting unused fields) β
β β’ Under-fetching (need another request) β
β β’ API versioning challenges β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GraphQL β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β POST /graphql β
β { β
β user(id: 1) { β
β name β
β posts { title } β
β } β
β } β
β β
β β
Benefits: β
β β’ Single request β
β β’ Get exactly what you need β
β β’ Strongly typed β
β β’ Self-documenting β
β β’ No versioning needed β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Client β β HTTP β β GraphQL β β Schema β
β Application β β Server β β Runtime β β + Types β
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β β β
β 1. GraphQL Query β β β
β βββββββββββββββββββΆ β β
β β 2. Parse Query β β
β β βββββββββββββββββββΆ β
β β β 3. Validate β
β β β βββββββββββββββββββΆ
β β β β
β β β 4. Execute β
β β ββββββββββββββββββββ (Field Resolution)
β β β β
β 5. JSON Response β β β
β βββββββββββββββββββ β β
query GetUserProfile {
user(id: "123") {
name
email
posts {
title
publishedAt
}
}
}
Document
βββ Operation (Query)
βββ Field: user
β βββ Argument: id = "123"
β βββ SelectionSet
β βββ Field: name
β βββ Field: email
β βββ Field: posts
β βββ SelectionSet
β βββ Field: title
β βββ Field: publishedAt
β
Field 'user' exists on Query type
β
Argument 'id' is valid for user field
β
Fields 'name', 'email' exist on User type
β
Field 'posts' returns [Post] type
β
Fields 'title', 'publishedAt' exist on Post type
Execution Tree:
βββ user(id: "123") β Call user resolver
βββ name β Return user.name
βββ email β Return user.email
βββ posts β Call posts resolver
βββ [0].title β Return post1.title
βββ [0].publishedAt β Return post1.publishedAt
βββ [1].title β Return post2.title
βββ [1].publishedAt β Return post2.publishedAt
{
"data": {
"user": {
"name": "John Doe",
"email": "john@example.com",
"posts": [
{
"title": "GraphQL is Amazing",
"publishedAt": "2024-01-15"
},
{
"title": "Building APIs with Rust",
"publishedAt": "2024-01-20"
}
]
}
}
}
The schema is the contract between client and server:
# Object Type - describes data structure
type User {
id: ID! # Non-null ID scalar
name: String! # Non-null String scalar
email: String # Nullable String scalar
age: Int # Nullable Integer scalar
posts: [Post!]! # Non-null list of non-null Posts
}
type Post {
id: ID!
title: String!
content: String!
author: User! # Connection back to User
tags: [String!] # List of non-null strings
}
# Root Query Type - entry points
type Query {
user(id: ID!): User # Get user by ID
users: [User!]! # Get all users
post(id: ID!): Post # Get post by ID
searchPosts(query: String!): [Post!]! # Search posts
}
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GraphQL Types β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Scalar Types (Leaf nodes) β
β βββ Built-in: String, Int, Float, Boolean, ID β
β βββ Custom: DateTime, Email, URL, JSON β
β β
β Object Types (Complex structures) β
β βββ Fields with other types β
β βββ Can implement interfaces β
β βββ Can be part of unions β
β β
β Interface Types (Abstract contracts) β
β βββ Define common fields β
β βββ Implemented by objects β
β β
β Union Types (One of many types) β
β βββ SearchResult = User | Post | Comment β
β βββ Used for heterogeneous collections β
β β
β Enum Types (Limited values) β
β βββ Status = DRAFT | PUBLISHED | ARCHIVED β
β βββ Provides type safety β
β β
β Input Types (For arguments) β
β βββ CreateUserInput { name: String!, email: String! } β
β βββ Used in mutations and query arguments β
β β
β Type Modifiers β
β βββ Non-Null: String! (required) β
β βββ List: [String] (array of strings) β
β βββ Non-Null List: [String!]! (required array of required) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Query: { user(id: "123") { name, posts { title } } }
Resolution Process:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 1: Resolve Root Field β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user(id: "123") β β
β β βββ Call: UserResolver.user(id: "123") β β
β β βββ Returns: User { id: "123", name: "John", ... } β β
β β βββ Type: User β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β Step 2: Resolve Object Fields β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user.name β β
β β βββ Direct property access β β
β β βββ Returns: "John" β β
β β βββ Type: String! β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β Step 3: Resolve Nested Objects β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user.posts β β
β β βββ Call: PostResolver.posts(user: User) β β
β β βββ Returns: [Post{title: "..."}, Post{title: "..."}] β β
β β βββ Type: [Post!]! β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β Step 4: Resolve List Items β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β posts[0].title, posts[1].title β β
β β βββ Direct property access for each post β β
β β βββ Returns: ["Post 1 Title", "Post 2 Title"] β β
β β βββ Type: String! (for each) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Final Result:
{
"data": {
"user": {
"name": "John",
"posts": [
{ "title": "Post 1 Title" },
{ "title": "Post 2 Title" }
]
}
}
}
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β QUERIES β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Purpose: Read data (like HTTP GET) β
β Side Effects: None (idempotent) β
β Execution: Can run in parallel β
β Caching: Safe to cache results β
β β
β query GetUser($id: ID!) { β
β user(id: $id) { β
β name β
β email β
β } β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MUTATIONS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Purpose: Modify data (like HTTP POST/PUT/DELETE) β
β Side Effects: Creates, updates, or deletes data β
β Execution: Always sequential (one by one) β
β Caching: Should not be cached β
β β
β mutation CreateUser($input: CreateUserInput!) { β
β createUser(input: $input) { β
β id β
β name β
β email β
β } β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SUBSCRIPTIONS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Purpose: Real-time updates (like WebSocket) β
β Side Effects: Establishes persistent connection β
β Execution: Long-lived connection β
β Caching: Not applicable β
β β
β subscription MessageAdded($chatId: ID!) { β
β messageAdded(chatId: $chatId) { β
β id β
β text β
β user { name } β
β } β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
GraphQL Request with Variables:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β { β
β "query": "query GetUser($userId: ID!, $includeEmail: Boolean!) { β
β user(id: $userId) { β
β name β
β email @include(if: $includeEmail) β
β } β
β }", β
β "variables": { β
β "userId": "123", β
β "includeEmail": true β
β } β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Variable Substitution: β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β $userId β "123" β β
β β $includeEmail β true β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β Effective Query: β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user(id: "123") { β β
β β name β β
β β email @include(if: true) // Will be included β β
β β } β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
GraphQL has a structured approach to error handling:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GraphQL Response β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β { β
β "data": { // Partial data (what succeeded) β
β "user": { β
β "name": "John", β
β "email": null // Failed field returns null β
β } β
β }, β
β "errors": [ // Detailed error information β
β { β
β "message": "Email service unavailable", β
β "path": ["user", "email"], // Location of error β
β "locations": [{"line": 4, "column": 5}], β
β "extensions": { β
β "code": "SERVICE_UNAVAILABLE", β
β "timestamp": "2024-01-15T10:30:00Z" β
β } β
β } β
β ] β
β } β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Field Resolution Error Propagation:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β Non-null field error β Propagates up to parent β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user { β β
β β name! β Error here (non-null) β β
β β email β β
β β } β β
β β β β
β β Result: user becomes null, error recorded β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Nullable field error β Field becomes null β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β user { β β
β β name β β
β β email β Error here (nullable) β β
β β } β β
β β β β
β β Result: email becomes null, error recorded, user remains β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β GraphQL-RS Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β HTTP Layer β β Presentation β β
β β (Axum/Warp) βββββΊβ Layer β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β Infrastructure β β Application β β
β β Layer βββββΊβ Layer β β
β β β’ Query Parser β β β’ Use Cases β β
β β β’ Schema Parser β β β’ Services β β
β β β’ Lexer β βββββββββββββββββββ β
β βββββββββββββββββββ β β
β β β
β βββββββββββββββββββ β
β β Domain Layer β β
β β β’ Entities β β
β β β’ Value Objects β β
β β β’ Services β β
β β β’ Events β β
β βββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HTTP Request β GraphQL Runtime β Response
β β β
βΌ βΌ βΌ
ββββββββββββ ββββββββββββββββ ββββββββββββ
β POST β β Parse β β JSON β
β /graphql βββββΆβ Validate βββββΆβ Response β
β β β Execute β β β
ββββββββββββ ββββββββββββββββ ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Our Rust Components β
β β
β 1. QueryParser β
β β’ Lexical Analysis β
β β’ Syntax Parsing β
β β
β 2. SchemaValidator β
β β’ Type Checking β
β β’ Rule Validation β
β β
β 3. QueryExecutor β
β β’ Field Resolution β
β β’ Data Fetching β
β β
β 4. ResponseBuilder β
β β’ Error Formatting β
β β’ JSON Serialization β
ββββββββββββββββββββββββββββ
The schema serves as the single contract between frontend and backend teams.
Every field, argument, and return type is explicitly defined and validated.
GraphQL APIs are self-documenting through introspection queries.
Tools like GraphQL Playground, Apollo Studio, and IDE extensions provide excellent DX.
Now that you understand GraphQL fundamentals, explore:
This foundation will help you understand how each component works together to create a complete GraphQL server! π
Clients specify exactly what data they need:
query GetUser {
user(id: "123") {
id
name
posts {
id
title
}
}
}
Modify data on the server:
mutation CreateUser {
createUser(input: {
name: "John Doe"
email: "john@example.com"
}) {
id
name
}
}
Real-time data updates:
subscription PostCreated {
postCreated {
id
title
author {
name
}
}
}
Aspect | GraphQL | REST |
---|---|---|
Endpoints | Single endpoint | Multiple endpoints |
Data Fetching | Precise, client-controlled | Fixed structure |
Over-fetching | Eliminated | Common issue |
Versioning | Not needed | Required |
Caching | Complex | Simple (HTTP caching) |
Learning Curve | Steeper | Gentler |
Understanding these fundamentals is crucial for implementing a GraphQL server. In the next sections, weβll dive into: