Let’s address the elephant in the room right away: Most of the APIs we call "RESTful" are actually fakes.
If you are building or consuming APIs that look like /api/users/123 or /api/orders/submit, you aren't really doing REST. You are doing RPC-over-HTTP (or what we affectionately call "REST-ish").
Why does this matter? Because you are missing the defining constraint of REST. You are missing the engine that makes the web so resilient: HATEOAS.
Don't worry if that acronym sounds intimidating. Let’s break it down into plain English.
The Website Analogy (A Lightbulb Moment)
Roy T. Fielding—the guy who literally defined REST—insists that a true REST API must act like a website. Think about your last online shopping experience.
Did you memorize the URL for the "Checkout" page? Did you hardcode the address for the "Returns" section in your brain? No. You just read the screen, saw a button that said "Proceed to Checkout," and clicked it. The website told you what you could do next.
That is the heart of HATEOAS (Hypermedia As The Engine Of Application State). The server tells the client what actions are available, rather than the client guessing or relying on an external manual.
What Exactly is "Hypertext/Hypermedia" Anyway?
Here is the beautiful thing: Hypertext doesn't mean "HTML in a browser." Roy Fielding clarified this perfectly:
“Hypertext is the simultaneous presentation of information and controls such that the information becomes the affordance through which the user obtains choices and selects actions.”
In simple terms: The data itself dictates the next steps. Machines can follow these links when they understand the data format.
To prove this isn’t just theoretical, let’s look at how this plays out in the real world, from human browsers to machine-to-machine communication.
Examples: Hypertext in Action
1. HTML (The Human Experience)
We all know this one. When you load a product page, you get the data (price, stock) and a control (the "Add to Cart" button) in the same package.
The Server Response:
<div class="product">
<h1>Wireless Headphones</h1>
<p>$199.99</p>
<form action="/cart/items" method="POST">
<input type="hidden" name="product_id" value="prod_987">
<button type="submit">Add to Cart</button>
</form>
</div>
Why it Works: The browser doesn't know what /cart/items is before it loads the page. It discovers that URL in the payload and presents it to you as a clickable button. The client (the browser) just understands HTML.
2. HAL JSON (Machine-to-Machine)
Now, let’s get nerdy. What if a machine (an automated bot) needs to check an order? Instead of hardcoding a URL like /orders/1024/pay, the server tells the bot what to do.
The Server Response:
{
"order_id": "ord_1024",
"status": "awaiting_payment",
"_links": {
"self": { "href": "/orders/ord_1024" },
"payment": { "href": "/orders/ord_1024/pay" },
"cancel": { "href": "/orders/ord_1024/cancel" }
}
}
The Usage (The "Ah-Ha!" Moment): Instead of coding POST /orders/ord_1024/pay into the client, the bot looks for the payment link.
// The bot doesn't hardcode the URL!
const paymentUrl = order._links.payment.href;
await fetch(paymentUrl, { method: 'POST' });
The Magic: If the URL changes tomorrow to /payments/checkout?order=1024, the bot still works. No code changes required. Furthermore, if the order is already paid, the server simply removes the payment link, preventing the bot from trying to pay twice.
3. JSON-LD + Hydra (The Intelligent Automaton)
For the truly decoupled systems, we use Semantic Web standards. This tells the client how to act, not just where to go.
The Server Response:
{
"@id": "/users/johndoe",
"@type": "Person",
"name": "John Doe",
"operation": [
{
"@type": "ReplaceResourceOperation",
"method": "PUT",
"expects": "http://schema.org/Person",
"title": "Update profile"
}
]
}
Why it's Powerful: The client doesn't need an OpenAPI spec or a PDF manual. The server tells the client: "To update this, send a PUT request here, and send me a 'Person' schema." The API is literally self-documenting.
Summary: Fielding's Core Principles (Cheat Sheet)
If you want to build truly RESTful APIs, you need to adopt these three rules:
- The Affordance Principle: The data tells you what you can do next. If you are an admin, you see an "Edit" link. If you are a guest, that link vanishes. State transitions are driven by the payload.
- No Hardcoding: Your client should only hardcode the root URL (e.g.,
api.example.com). Every other API call is made by following the breadcrumbs (links) in the previous response. - Format-Driven: The client shouldn't know your specific API rules. It only needs to know the media type standard (like
application/hal+json).
Final Thoughts
Building true RESTful APIs with HATEOAS takes more initial effort than just spinning up a bunch of endpoints. However, it decouples your client and server indefinitely. It allows your API to evolve without breaking millions of mobile apps or frontend builds.
Stop hardcoding paths. Start delivering controls with your data. That is how the web was designed to work.



