GraphQL: Schema, Operations, and Federation

Table of Contents

Concepts

GraphQL is a specification for an API query language and server engine capable of executing such queries.

  • Document has many operations or fragments (executables) or type system information
  • Operation types may be queries, mutations, and subscriptions

Contrasting REST

  • partials
  • versions
  • fields

Parsing

  • Whitespace and line terminations are as expected
  • Tokens
  • The "query" keyword and name may not be present for [{ field }]

Operations

  • query: read-only fetch
  • mutation: write + fetch
  • subscription: response to source events

Selection Sets

  {
    id
    firstName
    lastName
  }
  • Can contain aliases

Types

  • ID
  • String
  • DateTime

Schemas

The SDL provides a language for describing the type system for GraphQL.

Schema Root

Fragments

  query withFragments {
    user(id: 4) {
      friends(first: 10) {
        ...friendFields
      }
      mutualFriends(first: 10) {
        ...friendFields
      }
    }
  }

  fragment friendFields on User {
    id
    name
    profilePic(size: 50)
  }

Queries

Variables

Mutations

Enums

Abstract Types

interface Animal {
  name: String!
}

interface Plant {
  genus: String!
  species: String!
}

Unions

union Entity = Plant | Animal

Federation

Maintaining GraphQL

Tools

GraphQL Playground

Mocking

npm install -g get-graphql-schema graphql-cli graphql-faker
mkdir t && cd t
# graphql init

get-graphql-schema https://$HOST/graphql/ > schema.graphql
graphql-faker schema.graphql
open http://localhost:9002/editor

Reading

Production Ready GraphQL

An Introduction to GraphQL

  • [ ] An Introduction to GraphQL
  • [ ] One-Size-Fits-All
  • [ ] Let’s Go Back in Time
  • [ ] Enter GraphQL
  • [ ] Type System
  • [ ] Introspection

GraphQL Schema Design

  • [ ] What Makes an API Great?
  • [ ] Design First
  • [ ] Client First
  • [ ] Naming
  • [ ] Descriptions
  • [ ] Use the Schema, Luke!
  • [ ] Expressive Schemas
  • [ ] Specific or Generic
  • [ ] The Relay Specification
  • [ ] Lists & Pagination
  • [ ] Sharing Types
  • [ ] Global Identification
  • [ ] Nullability
  • [ ] Abstract Types
  • [ ] Designing for Static Queries
  • [ ] Mutations
  • [ ] Fine-Grained or Coarse-Grained
  • [ ] Errors
  • [ ] Schema Organization
  • [ ] Asynchronous Behavior
  • [ ] Data-Driven Schema vs Use-Case-Driven Schema

Implementing GraphQL Servers

  • [ ] GraphQL Server Basics
  • [ ] Code First vs SchemaFirst
  • [ ] Generating SDL Artifacts
  • [ ] Resolver Design
  • [ ] Schema Metadata
  • [ ] Multiple Schemas
  • [ ] Modular Schemas
  • [ ] Testing

Security

  • [ ] Rate Limiting
  • [ ] Blocking Abusive Queries
  • [ ] Timeouts
  • [ ] Authentication
  • [ ] Authorization
  • [ ] Blocking Introspection
  • [ ] Persisted Queries

Performance & Monitoring

  • [ ] Monitoring
  • [ ] The N+1 Problem and the Dataloader Pattern
  • [ ] Caching
  • [ ] Compiled Queries

Tooling

  • [ ] Linting
  • [ ] Analytics

Workflow

  • [ ] Design
  • [ ] Review
  • [ ] Development
  • [ ] Publish
  • [ ] Analyze Ship

Public GraphQL APIs

  • [ ] Is GraphQL a Good Choice for Public APIs
  • [ ] Lack of Conventions
  • [ ] With Great Power comes Great Responsibility

GraphQL in a Distributed Architecture

  • [ ] GraphQL API Gateway
  • [ ] GraphQL as a BFF
  • [ ] Service Communication

Versioning

  • [ ] API Versioning is Never Fun
  • [ ] Versioning GraphQL is Possible
  • [ ] Continuous Evolution
  • [ ] Change Management

Documenting GraphQL APIs

  • [ ] Documentation Generators
  • [ ] The What, Not Just the How
  • [ ] Workflows and Use Cases
  • [ ] Example / Pre-Made Queries
  • [ ] Changelogs
  • [ ] Upcoming Changes

Migrating From Other API Styles

  • [ ] Generators
  • [ ] REST & GraphQL Alongside

Videos

Conferences

GraphQL Summit 2020

GraphQL in Production

  • Paypal, Shopify, Priceline, American
  • Invest in tooling
  • Look at the execution
  • Measure timing
  • Public APIs can be difficult
  • How teams roll out GraphQL
  • Schema design shouldn't just map REST
  • Error handling
  • Caching
  • Providence of data and finding owner of data
  • Collaborating on the features with Product and Engineering
  • Duplicated data
  • Be patient when evangelizing GraphQL

Request lifecycle and resolver execution

A GraphQL request — whether query, mutation, or subscription — funnels through a single schema, then expands into a resolver tree. The N+1 problem is the dominant performance concern at the resolver layer; the DataLoader pattern (request-scoped batching + caching) is the canonical fix and is what makes a deeply-nested resolver tree viable against heterogeneous data sources.

// GraphQL request lifecycle — operations -> schema -> resolver tree -> batched sources
digraph graphql_resolver {
    rankdir=LR;
    graph [bgcolor="white", fontname="Helvetica", fontsize=11,
           pad="0.3", nodesep="0.3", ranksep="0.45"];
    node  [shape=box, style="rounded,filled", fontname="Helvetica",
           fontsize=10, fillcolor="#f5f5f5", color="#888"];
    edge  [color="#aaa"];

    // Client operations
    subgraph cluster_ops {
        label="Client operations"; labeljust="l";
        color="#369"; fontcolor="#369"; style="rounded";
        q   [label="query\n{ user { posts } }",      color="#369"];
        m   [label="mutation\n{ createPost(...) }",  color="#369"];
        s   [label="subscription\n{ postAdded }",    color="#369"];
    }

    // Schema gate (single funnel)
    schema [label="Schema\nparse · validate · plan",
            shape=box, style="rounded,filled,bold",
            fillcolor="#f5f5f5", color="#333", fontsize=11];

    q -> schema [color="#369"];
    m -> schema [color="#369"];
    s -> schema [color="#369"];

    // Resolver tree
    subgraph cluster_resolvers {
        label="Resolver tree (per request)"; labeljust="l";
        color="#693"; fontcolor="#693"; style="rounded";
        rRoot  [label="Query.user\n(parent resolver)", color="#693"];
        rPosts [label="User.posts\n(child resolver)",  color="#693"];
        rAuth  [label="Post.author\n(child resolver)", color="#693"];
        rRoot -> rPosts [color="#693"];
        rPosts -> rAuth [color="#693"];
    }

    schema -> rRoot [color="#aaa"];

    // DataLoader batching layer
    subgraph cluster_loader {
        label="DataLoader (request-scoped batch + cache)"; labeljust="l";
        color="#d63"; fontcolor="#d63"; style="rounded";
        dlUser [label="userById\nbatch(ids)",   color="#d63"];
        dlPost [label="postsByUser\nbatch(uids)", color="#d63"];
        dlAuth [label="userById\n(cache hit)",  color="#d63"];
    }

    rRoot  -> dlUser [color="#d63"];
    rPosts -> dlPost [color="#d63"];
    rAuth  -> dlAuth [color="#d63", style=dashed];

    // Data sources
    subgraph cluster_sources {
        label="Data sources"; labeljust="l";
        color="#639"; fontcolor="#639"; style="rounded";
        rest [label="REST\n(legacy users API)", color="#639"];
        db   [label="Postgres\n(posts table)",  color="#639"];
        grpc [label="gRPC\n(auth service)",     color="#639"];
    }

    dlUser -> rest [color="#639"];
    dlPost -> db   [color="#639"];
    dlAuth -> grpc [color="#639"];
}

diagram-resolver.png

Related notes

Postscript (2026)

The GraphQL ecosystem has consolidated sharply since these notes were first written. Schema stitching is deprecated in favour of Apollo Federation v2, and the reference gateway is now the Rust-based Apollo Router, which replaced the Node.js @apollo/gateway for production deployments and brought query-planning latency down by an order of magnitude. The GraphQL over HTTP specification (now a stable working draft from the GraphQL Foundation) finally pins down status codes, content negotiation, and the application/graphql-response+json media type — ending years of "every server does it differently". On the security side, persisted queries have been rebranded as Trusted Documents: clients send a hash, the server executes only registered operations, and arbitrary-query introspection is closed off in production. For servers, GraphQL Yoga and GraphQL Mesh (the latter exposing REST, gRPC, OpenAPI, and SOAP as a unified GraphQL surface) have largely displaced bespoke Apollo Server stacks for new projects. The persistent question — GraphQL vs tRPC vs gRPC-web — has settled into rough consensus: GraphQL for cross-team public/partner APIs, tRPC for single-team TypeScript monorepos, gRPC-web for service-to-service where typed RPC beats query flexibility.

Author: Jason Walsh

j@wal.sh

Last Updated: 2026-04-19 13:09:56

build: 2026-04-19 13:23 | sha: e35a0a3