GraphQL — Basics
GraphQL — Basics
Section titled “GraphQL — Basics”What it is
Section titled “What it is”Query language + runtime for APIs. Single endpoint (typically POST /graphql); client specifies exactly what fields to fetch.
Core concepts
Section titled “Core concepts”- Schema — type system (SDL: schema definition language).
- Query — read.
- Mutation — write (also returns data).
- Subscription — long-lived stream (typically over WebSocket).
- Resolver — function returning value for a field.
- Context — per-request state (auth, db, dataloaders).
Type system
Section titled “Type system”scalar DateTime
type User { id: ID! email: String! posts(limit: Int = 10): [Post!]!}
type Post { id: ID! title: String! body: String author: User!}
input CreatePostInput { title: String! body: String}
type Query { user(id: ID!): User feed(cursor: String, limit: Int = 20): FeedPage!}
type Mutation { createPost(input: CreatePostInput!): Post!}
type Subscription { postCreated(authorId: ID!): Post!}! = non-null. [T!]! = non-null list of non-null T.
Built-in scalars: Int, Float, String, Boolean, ID. Custom scalars common (DateTime, JSON, EmailAddress).
Operations
Section titled “Operations”query GetUser($id: ID!) { user(id: $id) { id email posts(limit: 5) { id title } }}Variables passed alongside; named operations easier to debug/cache.
Fragments for reuse:
fragment UserFields on User { id email name }
query { user(id: "1") { ...UserFields } }Resolvers
Section titled “Resolvers”const resolvers = { Query: { user: (_, { id }, ctx) => ctx.db.users.find(id), }, User: { posts: (parent, { limit }, ctx) => ctx.db.posts.byAuthor(parent.id, limit), }, Mutation: { createPost: (_, { input }, ctx) => ctx.db.posts.create({ ...input, authorId: ctx.user.id }), },};Each resolver receives: (parent, args, context, info).
Errors
Section titled “Errors”- Errors don’t fail the whole response — partial data +
errorsarray per field. - Standardize error shape:
code,message,path. Useextensionsfield.
{ "data": { "user": null }, "errors": [{ "message": "not found", "path": ["user"], "extensions": { "code": "NOT_FOUND" } }]}Pagination
Section titled “Pagination”- Offset — simple, problematic at scale.
- Relay cursor — standard:
edges,cursor,pageInfo { hasNextPage, endCursor }.
type FeedPage { edges: [FeedEdge!]! pageInfo: PageInfo!}type FeedEdge { node: Post! cursor: String! }type PageInfo { hasNextPage: Boolean! endCursor: String }Subscriptions
Section titled “Subscriptions”- Typically WebSocket (
graphql-wsprotocol). Server pushes events. - Use cases: live updates, chat, dashboards.
- Backed by pub/sub (Redis, Kafka).
Client tools
Section titled “Client tools”- Apollo Client, urql, Relay (most strict, used at Meta).
- Fragment colocation: each component declares its data needs.
- Persisted queries: send query hash, server stores actual query — saves bandwidth, improves caching.
Ecosystem
Section titled “Ecosystem”- Servers: Apollo Server, GraphQL Yoga, Mercurius (Fastify), graphql-ruby, gqlgen (Go), Strawberry (Python).
- Federation: Apollo Federation, GraphQL Mesh, Hot Chocolate (.NET).
- Tooling: GraphQL Code Generator (typed clients), Apollo Studio (schema registry), Hasura/PostGraphile (auto-generated from DB).
When to use / avoid
Section titled “When to use / avoid”Use when:
- Many clients with different needs (mobile, web, partner).
- Aggregating multiple downstream services.
- Rapid frontend iteration without backend changes.
Avoid when:
- Simple CRUD with one client — REST is less complex.
- File uploads / streaming bytes.
- Caching at HTTP layer matters (GraphQL POSTs are uncacheable by default — use persisted queries + GET).
- Public API where you want HTTP semantics.