# REST and GraphQL

Two API styles: REST exposes resources over HTTP verbs, GraphQL exposes a schema clients query for exactly what they need.

**Rests on:** API Testing

*Software Engineering · Software Architecture*


## Why learn this

You are here because you need to understand how two pieces of software talk to each other over the internet. REST and GraphQL are the two most common ways to build that conversation. Mastering this unlocks: reading and writing your own API endpoints (specific addresses where software sends requests), understanding how a frontend (a mobile app or a browser page) fetches data from a backend server, debugging 'why is this request 404' (not found) and 'why is this response so slow', and making architectural decisions about which style to use for a new system. Later, when you work with AI, you will call APIs constantly — to send data to a model or to get results back — and knowing what is happening inside those API calls will separate you from someone who just copies code. This concept is the doorway to your future work with real systems, so it is the last pure software concept you need before you start building things that touch AI services.


## The intuition

Think of two people trying to exchange information. There is a request — the asker says something — and there is a response — the other person answers. REST and GraphQL are two different sets of rules for how that ask and answer work over the internet. The word 'API' just means the agreed set of rules. A restaurant menu is an API: the kitchen has decided that if you say 'chicken curry' you get chicken curry, but if you say 'pass me the salt' they won't look at you. Similarly, a server has decided what requests it responds to and what each response looks like. REST is like ordering from a fixed menu: the menu lists dishes, you pick one, and you get a standard plate. You cannot ask for 'chicken without the onions, extra rice, but only the left half' — the kitchen has pre-defined the dishes, and if you want something slightly different you must order a different dish or accept what comes. GraphQL is like going to a buffet where you can say 'give me the chicken, but only the dark meat, and half the rice' and the server plate is exactly what you asked for, nothing more, nothing less. Both get you food, but the experience and the flexibility differ. On the internet, the 'dish' in REST is a resource — a user, a product, a post. The 'menu' is a set of addresses called URLs, and you use standard verbs like GET (look at the menu) or POST (order something) to interact. GraphQL has no such fixed menu; it has a single address, and you send a question describing exactly the shape of the answer you want. So the intuition: REST is about getting the whole thing; GraphQL is about asking for exactly the pieces you need.


## An analogy

Imagine you want to buy a book at a large bookshop. The book is a resource. In REST, you go to the counter and say 'I want book number 12345' (a URL) and the clerk hands you the entire book — cover, all pages, even the blank ones. If you only wanted one chapter, you still receive the whole thing, because the shop has decided that the unit of exchange is the book. Now suppose you wanted just the price and the author's name — in REST you still get the whole book or you need a different 'edition' (a different URL that gives a smaller version, but that version is still pre-defined). That is exactly what happens: a server often returns a big JSON object (a structured text format used for data transfer) with many fields, and the client has to filter out what it doesn't need. In GraphQL, instead of going to the counter, you go to a special order desk. You write a note: 'Give me the price and the author's name for book 12345, and also the first paragraph of the first chapter' — and the desk returns only those bits, neatly put together. The bookshop hasn't given you the whole book; they've efficiently extracted what you asked for. The catch: the bookshop has to have a special system to understand your note. The counter works for everybody, but the order desk needs a manual that explains all possible combinations — this is the 'schema' (the map of all available data). Where the analogy stops working: in a real bookshop, the order desk would be a human who knows the shop's inventory. In software, GraphQL still needs a server that has all the data available, so the request may have to fetch several different data sources behind the scenes. Also, REST can give you exactly what you want if the designer of the API has created the right endpoint; the problem is that you (the client) cannot change the server's menu. GraphQL gives the client flexibility, but it moves the work to the server — the server must be able to parse the query and fetch the data efficiently. In a bookshop, the clerk can retrieve a whole book faster than they can assemble a custom package from different shelves.


## Definition

REST is an API style where a server organizes its data into resources identified by URLs, and clients use standard HTTP methods (like GET, POST, PUT, DELETE) to perform operations on those resources, always receiving a fixed, pre-defined representation. GraphQL is a query language and runtime that lets a client send a nested query describing exactly which fields and which combined data it wants, and the server responds with precisely that structure.


## How it connects

You already know from your notes on Software Architecture that the way components communicate is an architectural decision that is expensive to reverse. Choosing between REST and GraphQL is exactly such a decision: you are choosing the boundary between your client and your server, and the dependency direction (the client depends on the server's interface). Your notes on Cohesion and Coupling apply here: cohesion means how closely related the parts of a single module are (high cohesion is good), while coupling means how much one module relies on the internal details of another (tight coupling is bad). A REST API with a well-chosen set of resources has high cohesion (each resource is a focused unit), while a GraphQL schema can become a giant grab-bag if not carefully shaped, lowering cohesion. Tight coupling between client and server is what GraphQL tries to break by letting the client request exactly what it needs, but it does so by introducing a shared schema that both sides must agree on — a different form of coupling. Your notes on Dependency Inversion are relevant: this principle means high-level modules should not depend on low-level details, but rather on abstractions. The client should depend on the API's interface (the schema in GraphQL, the resource descriptions in REST) rather than on a concrete implementation. Both styles are 'ports' and 'adapters' in hexagonal architecture: a port is an interface that defines how external systems interact with your core logic, and an adapter translates between that interface and the specific technology being used (like HTTP). The API acts as the port, and the HTTP implementation acts as the adapter.


## The mathematics

This concept rests on the branch of mathematics called logic and set theory — specifically, the idea of a set, which is a collection of things, and a function, which is a rule that takes one element from a set and gives you one element from another set. You need this because an API is really a big set of possible requests and a rule that maps each request to a response. In REST, that mapping is simple: a URL and a verb determine a fixed response. In GraphQL, the rule is more complex: a query is a description of a shape, and the rule maps that shape to a piece of data from the database. You don't need to do calculations with numbers, but you do need to grasp that a request is like an input to a machine, and the response is the output. The 'arithmetic' here is not about addition but about counting and comparing: REST returns a whole set of fields, and you often get more than you need (over-fetching); GraphQL returns exactly the fields you asked for, so you can compare the number of fields. I'll teach you the idea of a set and a function in a moment with a simple example, and then show how a REST response is like a full set, while a GraphQL response is like choosing a subset.

Let R be the set of all fields the server can return for a resource. In REST, the response contains all fields in R: response_REST = R. In GraphQL, the client asks for a subset S ⊆ R, and the response contains exactly S: response_GraphQL = S. This is expressed with a set membership relation: every element s in S is in R (s ∈ R), but not every element r in R is necessarily in S.


## A worked example

```
Imagine a server that has information about three users. Each user has an ID (a number), a name, an age, and an email address. Let's call the users A, B, and C. User A: id=1, name="Alice", age=30, email="alice@example.com". User B: id=2, name="Bob", age=25, email="bob@example.com". User C: id=3, name="Carol", age=35, email="carol@example.com". In the REST style, if you request the resource for user 1 (e.g., GET /users/1), the server returns all four fields of that user. In a GraphQL-style query, you might ask for only the name and age of user 1, and the server returns just those.

Step 1: REST GET /users/1 -> response: {"id": 1, "name": "Alice", "age": 30, "email": "alice@example.com"}   # The server sends the whole record; the client receives 4 fields.
Step 2: GraphQL query: { user(id: 1) { name, age } } -> response: {"data": {"user": {"name": "Alice", "age": 30}}}   # The server sends only the two requested fields; the response has 2 fields.
Step 3: Counting fields: REST response has 4 fields; GraphQL response has 2 fields.   # This is the difference in what is delivered — GraphQL avoids sending the email when it's not needed.

Result: In this tiny example, REST returns 4 fields, GraphQL returns 2. That 50% reduction in payload is the practical effect. In real APIs with dozens of fields, GraphQL saves a lot of bandwidth and reduces the time the client takes to process the response.
```


## From scratch, in Python

```python
import json
from urllib.parse import urlparse

# --- RestClient: a tiny simulation of a REST client ---

def get_user_rest(server_data, user_id):
    """Return the full record for a user, like a REST GET."""
    # server_data is a list of dictionaries
    for user in server_data:
        if user["id"] == user_id:
            return user
    return None  # not found

# --- GraphQLClient: a tiny simulation of a GraphQL client ---

def graphql_query(server_data, query):
    """
    A very simplified GraphQL query processing.
    query is a string like 'name,age' meaning we want those fields.
    We only handle a single resource lookup by id for illustration.
    """
    # parse id and fields from a query string (simplified)
    # assume query has form 'user(id:1){name,age}'
    # We'll do a naive parse for illustration.
    if query.startswith('user(id:'):
        # find the id
        colon = query.index(':')
        open_brace = query.index('{', colon)
        close_brace = query.index('}', open_brace)
        id_str = query[colon+1:open_brace].strip(' )')
        user_id = int(id_str)
        fields_str = query[open_brace+1:close_brace]
        fields = [f.strip() for f in fields_str.split(',')]
        # find the user
        for user in server_data:
            if user["id"] == user_id:
                return {f: user[f] for f in fields}
    return None

# --- Use it ---
server_data = [
    {"id": 1, "name": "Alice", "age": 30, "email": "alice@example.com"},
    {"id": 2, "name": "Bob", "age": 25, "email": "bob@example.com"},
    {"id": 3, "name": "Carol", "age": 35, "email": "carol@example.com"}
]

# REST request
rest_result = get_user_rest(server_data, 1)
print("REST response:")
print(json.dumps(rest_result, indent=2))

# GraphQL request
query = "user(id:1){name,age}"
graphql_result = graphql_query(server_data, query)
print("GraphQL response:")
print(json.dumps(graphql_result, indent=2))
```


## What the code does

This code has two simplified functions that mimic the two styles.

First, we define a list of dictionaries `server_data`. A dictionary in Python is like a table with two columns: the key (a word like 'name') and the value (like 'Alice'). We have three dictionaries in the list, one per user.

The first function `get_user_rest` loops through the list, checking each user's `id`. When it finds a match, it returns the entire dictionary — all four fields. This is REST's behaviour: fixed, full representation.

The second function `graphql_query` takes a query string. We simulate a simplified GraphQL query like 'user(id:1){name,age}'. The function extracts the id (1) and the list of fields (['name', 'age']) using string methods. It then finds the user and builds a new dictionary containing only the requested fields. The `for f in fields` is a loop that goes through the field names one by one and pulls that value from the user dictionary. It uses a dictionary comprehension, which builds a new dictionary in one line: `{f: user[f] for f in fields}` — for each field name, it maps the name to the user's value.

Finally we call both functions and print the results with `json.dumps` which formats the dictionary with nice indentation so you can see the structure.

Running this will show REST returns all four fields, while GraphQL returns only the two requested. This is the core difference in action.


## Common misconceptions

**GraphQL is always better than REST** — GraphQL is newer and more flexible, so it should replace REST everywhere.

GraphQL adds complexity: you need a schema, resolvers, and careful query validation. For simple use cases, REST is simpler to build, cache, and reason about. Flexibility comes at a cost, and sometimes you don't need it. In fact: REST and GraphQL are both valid choices; the best one depends on the situation. REST is often better for simple public APIs and caching; GraphQL is better when multiple clients need different subsets of data.

**REST always over-fetches** — Every REST request returns the entire database record, so it is always wasteful.

REST APIs can be designed to return different representations (e.g., /users/1 returns full, /users/1?fields=name,age returns less). The over-fetching issue is a symptom of poorly designed endpoints, not an inherent trait. In fact: REST gives you full control over the response shape; the server designer decides what each resource returns. But because you cannot have a custom endpoint for every possible combination, you often either over-fetch or under-fetch, which is why GraphQL exists.

**GraphQL is a database query language** — GraphQL is just SQL for the web, a way to query the database directly.

GraphQL operates at the API layer, not the database. The client sends a query to the graphQL server, and the server fetches data from whatever sources it wants (database, another API, etc.). It doesn't execute raw SQL from the client. In fact: GraphQL is the contract between client and server; the server decides how to resolve the query, possibly from multiple sources, and returns the requested shape.


## In short

REST: fixed set of resources and verbs, simple and cacheable, but can over-fetch or require many round trips. GraphQL: a schema and a query language that returns exactly what you ask, flexible but more complex on the server. Use REST for simplicity and caching; use GraphQL when client data needs vary widely. The choice is an architectural trade-off between coupling, cohesion, and the 'ilities' you value most.


## Where this is used

REST and GraphQL are not AI-specific but are the plumbing through which AI systems are delivered. Here is how they appear in practice.

**Large Language Models (LLMs)**: When you use an LLM like ChatGPT, you are not typing directly into the model. You are sending a REST request to a server (often with a POST to a URL like /v1/chat/completions) with a JSON body containing the messages. The server runs the model and returns a JSON response with the generated text. The API is REST because it is simple and predictable — the request has a fixed format and the response is a standard structure. The model itself lives on the server, and the client never touches the weights.

**Small models (on-device)**: These do not usually call an external API; they run entirely on the phone or laptop. However, when they need to sync or update, they might call a REST endpoint to download new model weights or upload usage data. The API style here is often REST because the payload is large and fixed, and caching is beneficial. GraphQL would add overhead for little gain since the data is not nested or queryable from many sources.

**Retrieval-Augmented Generation (RAG)**: In RAG, you embed a user's query, search a vector database for similar documents, and then feed those documents to the LLM. The embedding model and the vector database are both accessed via APIs. The vector database (like Pinecone) uses a REST API to insert and query vectors. You send a POST with the vector, and the response contains a list of matches. REST is standard because the operations are simple and the payloads are fixed. GraphQL is rarely used here because the queries are not complex and the responses are small fixed structures.

**Agentic systems**: An agent that plans and calls tools often calls multiple APIs to perform actions. These APIs are almost always REST. The agent might call a calendar API (REST), a weather API (REST), and a database API (REST). Each call is an HTTP request with a fixed response format. The agent does not need the flexibility of GraphQL because it is calling each tool separately. However, if an agent needed to gather data from multiple tables in one go, GraphQL could reduce the number of round-trips. In practice, agent frameworks like LangChain use REST-based tool calls.

**Everyday applied ML**: When you build a recommendation system or a fraud detection model, you typically serve the model behind a REST endpoint. A client sends a feature vector as JSON, and the server returns a prediction. The model is wrapped in a web service (using Flask or FastAPI) that exposes a POST endpoint. This is the standard pattern because it is simple, language-agnostic, and easy to cache. In a production system with many microservices, each service exposes a REST API; a GraphQL gateway could aggregate several REST services to provide a single query interface for the frontend, but it is an extra layer that is not always justified.

**Where GraphQL shines**: In a mobile app that talks to a server with deeply nested data. The app needs only a few fields from a large object; sending the whole object wastes bandwidth. A GraphQL query gets exactly the needed fields in one round trip, avoiding over-fetching and multiple REST calls. That is why many large web apps (like GitHub's API) offer GraphQL. But it comes at a cost: the server must have a schema and a resolver for every query, which adds complexity, and caching becomes harder because the server does not know what the client will ask. So developers use REST for simple operations and GraphQL when client diversity justifies it.

**In practice**: A developer building a Machine Learning API will use a framework like Flask or FastAPI to define endpoints (e.g., @app.post('/predict')) and receive JSON. For GraphQL, they would use Apollo or Graphene to define a schema and resolvers. If they do it poorly — with REST — they might over-fetch and slow the client; if they do GraphQL poorly — with overly broad queries — they could cause denial-of-service by allowing huge nested queries that fetch the entire database.

The key to using this in the real world: choose REST for simple, resource-oriented, cacheable interfaces; choose GraphQL when you have multiple clients needing different shapes and the added server complexity is manageable. Your architectural notes on coupling and cohesion apply: REST gives loose coupling (client and server don't need to know each other deeply), while GraphQL introduces a shared contract (schema) that must evolve carefully.


---

Read this on the web: https://basavapurushottam.com/learn-ai/rest-and-graphql
