Skip to main content
GraphQL Fundamentals·Lesson 1 of 5

What is GraphQL?

GraphQL is a query language for APIs and a runtime that executes those queries. Instead of having many REST endpoints (/users, /users/1/posts, /users/1/posts/5/comments), you have one endpoint and clients ask for exactly the data they need — nothing more, nothing less.

REST vs GraphQL

With REST, fetching a user's profile plus their latest three posts might require two requests:

GET /users/42
GET /users/42/posts?limit=3

With GraphQL, one request:

query {
  user(id: 42) {
    name
    email
    posts(limit: 3) {
      title
      publishedAt
    }
  }
}

The server returns exactly that shape — no extra fields, no under-fetching.

The Schema

Everything in GraphQL is defined in a schema — a typed contract between client and server:

type User {
  id:    ID!
  name:  String!
  email: String!
  posts: [Post!]!
}

type Post {
  id:          ID!
  title:       String!
  publishedAt: String!
  author:      User!
}

type Query {
  user(id: ID!): User
  posts: [Post!]!
}

! means non-nullable. [Post!]! means a non-null list of non-null Post objects.

Scalar Types

TypeDescription
StringUTF-8 text
Int32-bit integer
FloatDouble-precision decimal
Booleantrue or false
IDUnique identifier (serialised as String)

You can also define custom scalars (e.g. Date, JSON).

Queries, Mutations, and Subscriptions

GraphQL has three operation types:

  • Query — read data (like GET)
  • Mutation — write data (like POST/PUT/DELETE)
  • Subscription — real-time event stream over WebSocket
# Query
query GetUser($id: ID!) {
  user(id: $id) { name email }
}

# Mutation
mutation CreatePost($title: String!, $authorId: ID!) {
  createPost(title: $title, authorId: $authorId) {
    id title
  }
}

# Subscription
subscription OnNewPost {
  postCreated { id title author { name } }
}

Making a GraphQL Request

GraphQL always uses POST with Content-Type: application/json. The body contains the query string and optional variables:

Ctrl+Enter
HTML
CSS
JS
Preview

Why GraphQL?

Advantages over REST:

  • No over-fetching (you only get what you ask for)
  • No under-fetching (get nested data in one request)
  • Strongly typed schema serves as living documentation
  • Introspection — clients can query the schema itself

Trade-offs:

  • More complex to set up than a simple REST API
  • Caching is harder (all requests go to one URL)
  • File uploads require extra configuration
  • N+1 query problem if resolvers aren't batched with DataLoader