advanced
GraphQL schema and operations
Model types, fields, queries, mutations, subscriptions, nullability, input types, and operation contracts deliberately.
GraphQL exposes a typed schema clients query with a single endpoint. Operations: **Query** (read), **Mutation** (write), **Subscription** (push).
type Order {
id: ID!
status: OrderStatus!
total: Money!
customer: Customer!
}
enum OrderStatus { PENDING SHIPPED CANCELLED }
input CreateOrderInput {
customerId: ID!
lineItems: [LineItemInput!]!
}
type Mutation {
createOrder(input: CreateOrderInput!): CreateOrderPayload!
}
type Query {
order(id: ID!): Order
orders(first: Int!, after: String): OrderConnection!
}
Design choices:
- **Nullability**: `!` only when the server always resolves; nullable for partial failures in lists.
- **Input types** separate from output types; avoid exposing internal storage shapes.
- **Connections** (Relay-style) for pagination: `edges { node cursor }`, `pageInfo`.
- **Payload types** for mutations: `{ order, errors }` or union results for domain failures.
On interviews: when GraphQL beats REST (flexible reads, mobile clients), cost of unbounded queries, and schema evolution (deprecated fields, @oneOf).
Common pitfalls: mirror of database tables in the graph, everything non-null, mutations that look like RPC with no input validation, and breaking clients by removing fields without deprecation.
The trade-off is client flexibility versus server predictability — enforce complexity limits and persisted operations in production.
Checklist:
- Model domain types, not tables.
- Deliberate nullability and pagination patterns.
- Deprecate before remove; additive schema changes.
- Validate inputs at the API boundary.