Client specifies exact fields needed — eliminates over-fetching and under-fetching.
# Query
query {
user(id: 1) {
name
email
posts(limit: 5) { title created_at }
}
}
# Mutation
mutation {
createPost(input: {title: "Docker", body: "..."}) {
id title created_at
}
}
# Schema (SDL)
type User {
id: ID!
name: String!
posts: [Post!]!
}
type Query {
user(id: ID!): User
posts(limit: Int): [Post!]!
}
# Single endpoint: POST /graphql