Logo Dark
Get In Touch

What Is GraphQL? Queries, Mutations and Types Explained

/
Web

Quick Summary: This beginner-friendly guide explains what GraphQL is and why it was created, compares it with REST using a real screen example, and shows how to read data with queries and change data with mutations. It then walks through every core GraphQL type (scalars, objects, lists, non-null, enums, input types, interfaces and unions) with a small example app you can follow along with.

Introduction

Think about two ways of ordering lunch. In the first, the restaurant sells fixed combos. You only want a burger and a drink, but the combo also comes with fries, a dessert, and a sauce you will never use. If you want something extra, you place another order.

In the second, you tell the waiter exactly what you want, and one tray arrives with exactly that.

REST APIs often feel like the first way. GraphQL is the second. It lets an app ask a server for the exact data it needs, across related items, in a single request.

Here we cover:

  • What GraphQL is and why it exists
  • How it differs from REST
  • How to read data (queries) and change data (mutations)
  • The types GraphQL uses to describe data: scalars, objects, lists, and more

All examples use one small app: an online store where a Seller sells a Product, and customers leave Reviews.

What Is GraphQL?

GraphQL is two things in one:

  • A query language. A way for the client to describe the data it wants.
  • A runtime. The server-side engine that checks that request against a typed schema and returns the result.

Three ideas sit at the heart of it:

  • The client chooses the fields. You ask for exactly what a screen needs, nothing more.
  • The schema is the contract. It lists every type, field and relationship the API offers.
  • Usually one endpoint. Most requests go to a single URL, commonly 

GraphQL began inside Facebook (now Meta) to serve its mobile apps. It was open-sourced in 2015 and is now looked after by the GraphQL Foundation.

Two things it is not:

  • It is not a database. It sits between your app and your data sources (databases, other APIs, services).
  • It is not a single product. GraphQL is a specification, and many tools implement it, such as Apollo Server, Spring for GraphQL, Netflix DGS, and Hot Chocolate.

Why Did GraphQL Appear?

The problem was never that REST is bad. The problem was getting the right data efficiently as apps grew more complex. Three pain points kept showing up.

  1. Over-fetching. The API sends more than the screen needs. A profile badge only needs a name and an avatar, but the endpoint returns the whole user object: address, phone, preferences, history.
  2. Under-fetching. One endpoint does not have everything the screen needs, so the app makes several calls and stitches the answers together.
  3. Changing UI needs. The web app, the mobile app, and a smart TV all want different fields. Every time a screen changes, someone has to adjust an endpoint.

GraphQL's answer is to let the client describe the shape of the response. The mindset changes from "which endpoint gives me this object?" to "what data does this screen need?"

GraphQL vs REST: What's the Difference?

Let's build one screen: a Product details page. It shows the product name, price, and status. It also shows the seller's name and a list of customer reviews.

With REST

The data lives in different places, so the app makes several calls:

GET /products/42          -> product details (plus many fields the page never shows)
GET /products/42/reviews  -> the reviews
GET /sellers/7            -> the seller's name

Three round trips, and each response carries extra data the screen throws away.

With GraphQL

The app sends one request to one endpoint:

query {
  product(id: "42") {
    name
    price
    status
    seller { name }
    reviews { comment }
  }
}

The server answers with exactly those fields and nothing else.

The main differences

RESTGraphQL
EndpointsMany resource endpointsUsually one /graphql endpoint
Response shapeDecided by the serverChosen by the client
Nested dataOften needs multiple callsRelated data can come back together
VersioningOften /v1, /v2Add new fields and deprecate old ones
ContractOpenAPI or similar toolingThe typed schema itself
CachingWorks naturally with HTTP and CDNsHarder, because requests usually go to one URL
File uploadNative and simpleNot part of the core spec, so usually kept on REST

Important: this is not "REST is old, GraphQL is the future." REST is often simpler for stable resources, public APIs, file transfers, and anything that benefits from HTTP caching. GraphQL shines when screens need nested data or different clients need different shapes. Many teams use both side by side.

The GraphQL Schema: Your API's Contract

Before a client can send a single query, the server publishes a schema. It is written in the Schema Definition Language (SDL) and describes everything that can be asked for.

Here is the schema for our online store:

enum ProductStatus {
  IN_STOCK
  OUT_OF_STOCK
}

type Seller {
  id: ID!
  name: String!
}

type Review {
  id: ID!
  comment: String!
  rating: Int!
}

type Product {
  id: ID!
  name: String!
  price: Float!
  status: ProductStatus!
  stockCount: Int
  seller: Seller!
  reviews: [Review!]!
}

input AddProductInput {
  name: String!
  price: Float!
  stockCount: Int
}

type Query {
  product(id: ID!): Product
  products: [Product!]!
}

type Mutation {
  addProduct(input: AddProductInput!): Product!
}

So the schema works like a menu: if something is not on it, the client cannot ask for it.

The server also checks every request against the schema before running any code. Ask for a field that does not exist, or pass the wrong type, and the request is rejected straight away.

The GraphQL Type System

Everything in a schema has a type. This is what lets GraphQL check requests before running them, and what powers autocomplete and code generation in tools. You only need a handful of types to get started.

1. Scalar types: single values

Scalars are the leaves of a query, the actual values. GraphQL has five built-in types:

ScalarWhat it holdsExample value
IntA signed 32-bit whole number25
FloatA decimal number499.99
StringText"Running Shoes"
Booleantrue or falsetrue
IDA unique identifier, sent as text"42"

Servers can also define custom scalars for things like dates and emails, for example, a DateTime scalar.

2. Object types: structured data

An object type is a named set of fields, and each field has its own type. It is how you describe a real-world thing such as a Product or a Seller.

type Product {
  id: ID!
  name: String!
  seller: Seller!
}

Fields can point to other object types, like seller above. That is how GraphQL builds a graph of related data and lets you walk from a product to its seller to anything else linked to that seller in a single query.

3. Lists: collections

Square brackets turn any type into a list.

reviews: [Review!]!

This reads as "a list of Review objects." In a query, you pick the fields you want for each item, and you get back an array.

4. Non-null: the exclamation mark

By default, any field in GraphQL can be null. Adding ! is a promise that the value will always be there.

  • name: String!
  • stockCount: Int

The ! becomes interesting when combined with lists. These four look similar but mean different things:

Written asCan the list itself be null?Can items inside be null?
[String]YesYes
[String!]YesNo
[String]!NoYes
[String!]!NoNo

The last one, [String!]!, is the most common and the easiest to work with.

5. Enum types: a fixed set of choices

An enum limits a field to a small list of allowed values.

enum ProductStatus {
  IN_STOCK
  OUT_OF_STOCK
  DISCONTINUED
}

6. Input types: structured arguments

Object types describe what the server returns. When a client needs to send a structured object, such as the details of a new product, it uses an input type (used mainly in mutations).

input AddProductInput {
  name: String!
  price: Float!
  stockCount: Int
}

7. Interfaces and unions

An interface is a set of fields that several types promise to share:

interface Item {
  id: ID!
  name: String!
}

type Gadget implements Item {
  id: ID!
  name: String!
  warrantyMonths: Int!
}

A union says "this field can be one of several types", without needing shared fields. For example, a search result could be either a Product or a Seller.

8. The root types: Query, Mutation, Subscription

These special object types are the entry points to your API. Every query starts at a field on Query, and every mutation starts at a field on Mutation.

type Query {
  product(id: ID!): Product
  products: [Product!]!
}

type Mutation {
  addProduct(input: AddProductInput!): Product!
}

If it is not reachable from one of these roots, a client cannot get to it.

Reading Data: The GraphQL Query

A query is a read-only operation. The client describes the exact response shape it wants.

query GetProduct($id: ID!) {
  product(id: $id) {
    name
    price
    status
    seller { name }
    reviews { comment }
  }
}

Variables are sent separately as JSON:

{ "id": "42" }

The response:

{
  "data": {
    "product": {
      "name": "Running Shoes",
      "price": 2499.5,
      "status": "IN_STOCK",
      "seller": { "name": "Urban Sports" },
      "reviews": [
        { "comment": "Very comfortable" },
        { "comment": "Good value for money" }
      ]
    }
  }
}

Notice: the response has the same shape as the query. Ask for five things, get five things. Ask for only the name, and you get only the name.

How the request travels

Over HTTP, the app sends a POST to the GraphQL endpoint with a small JSON body:

POST /graphql
{
  "query": "query GetProduct($id: ID!) { product(id: $id) { name } }",
  "variables": { "id": "42" }
}

Writing Data: The GraphQL Mutation

A mutation changes data on the server: create, update or delete. It looks like a query, but it starts with the word mutation.

mutation AddProduct($input: AddProductInput!) {
  addProduct(input: $input) {
    id
    name
    status
  }
}

Variables:

{
  "input": {
    "name": "Wireless Mouse",
    "price": 799.0,
    "stockCount": 25
  }
}

Response:

{
  "data": {
    "addProduct": {
      "id": "43",
      "name": "Wireless Mouse",
      "status": "IN_STOCK"
    }
  }
}

This shows a nice feature: a mutation can return data. After adding the product, we asked for its new ID, name, and status in the same request. The app does not need a second call to find out what happened.

GraphQL Query vs Mutation

QueryMutation
PurposeRead dataChange data (create, update, delete)
Side effectsNone; it should only readChanges server state
Keywordquerymutation
ExecutionFields may be resolved in parallelTop-level mutation fields run one after another
Exampleproduct(id: 42)addProduct(input: ...)

There is also a third operation type, the subscription. It opens a long-lived connection (usually a WebSocket) so the server can push live events, such as an order tracking page that updates as a parcel moves from packed to shipped.

Putting It All Together

Here is how the pieces connect for one simple flow.

  1. Add a product with a mutation. It uses the input type 
  2. The server stores it and returns the fields you asked for, including the enum status 
  3. Read it back with a query: pass the 
  4. The response mirrors your query, and the schema guarantees every value matches its declared type.

Conclusion

GraphQL is a simple idea: the client asks for exactly the fields it needs, the schema defines what is allowed, and the server answers in the same shape. You have now seen what it is, why it appeared, how it differs from REST, how queries read, and mutations write, and the types that make it all predictable.

If you remember only five things:

  1. The client asks for the fields it needs.
  2. The schema defines what is allowed.
  3. Query reads. Mutation changes.
  4. Nested data can come back in one request.
  5. The response has the same shape as the query.
Planning a GraphQL API for your product?
Hire GraphQL Developers

FAQs

What is GraphQL used for?

GraphQL is used to build APIs where the client asks for exactly the data it needs in one request. It suits screens that combine related data, like a product with its seller and reviews, and apps where web, mobile and other clients each need different fields from the same backend.

Is GraphQL better than REST?

Neither is better everywhere. GraphQL helps when screens need nested data or different clients need different shapes. REST is often simpler for stable resources, public APIs, file uploads and anything that relies on HTTP caching. Many teams use both side by side, picking whichever fits each part of the product.

Is GraphQL a database?

No. GraphQL is a query language and a server-side runtime that sits between your app and your data sources. Those sources can be databases, other APIs or internal services. The schema describes what clients can ask for, and the server fetches the data from wherever it actually lives.

What is the difference between a GraphQL query and a mutation?

A query only reads data and should have no side effects. A mutation creates, updates or deletes data on the server. Both look similar and can return fields in the same request. One difference: top-level fields in a query may run in parallel, while top-level mutation fields run one after another.

What is a GraphQL schema?

A GraphQL schema is the contract for your API. Written in the Schema Definition Language (SDL), it lists every type, field and relationship clients can request, plus the entry points on Query and Mutation. The server checks every request against it and rejects unknown fields or wrong types before running any code.

Jenish Dadhania
Assistant Software Engineer
Hey, I’m a Software Developer who enjoys turning coffee into code and complex problems into practical solutions. I work with Java, Spring Boot, React, databases, and AI to build clean, reliable, and scalable software. I enjoy exploring backend systems, designing better APIs, understanding system design, and experimenting with modern technologies and figuring out why something broke (and fixing it… eventually 😅). I believe great software isn’t just about making things work — it’s about writing code that is simple, maintainable, and makes sense even the next day.
India (HQ)

201, iSquare Corporate Park, Ahmedabad-380060, Gujarat, India

+91 77 97 977 977
Canada

24 Merlot Court, Timberlea, NS B3T 0C2, Canada

+1 902-333-0067

For Sales

YO@7SPAN.COM

Looking For Jobs

Apply Now
Making It Possible Light