· Goher K · Web Development · 15 min read

REST API vs RESTful API: Architectural Differences Explained in Depth

Understand key differences between a REST API and a RESTful API. Master Roy Fielding constraints, Richardson Maturity levels, HATEOAS, and API architecture.

Fact-Checked & Tested by Goher K · Principal Cloud Architect & Technical Consultant with 20+ years evaluating cloud infrastructure, deliverability protocols, and automation benchmarks.

1. The Industry Confusion: Synonym or Architectural Distinction?

In contemporary software engineering discussions, developers frequently use the terms REST API and RESTful API as interchangeable buzzwords. Job postings demand proficiency in “RESTful architecture,” while documentation portals like Stripe and GitHub advertise their public interfaces as “REST APIs.”

However, beneath the colloquial terminology lies a profound architectural distinction rooted in academic computer science, network protocols, and software design patterns.

┌────────────────────────────────────────────────────────────────────────┐
│                   THE ARCHITECTURAL SPECTRUM                           │
├───────────────────────────────┬────────────────────────────────────────┤
│ Term                          │ Formal Definition                      │
├───────────────────────────────┼────────────────────────────────────────┤
│ REST                          │ The theoretical architectural style    │
│ (Representational State       │ defined by Dr. Roy Fielding (2000)     │
│ Transfer)                     │ containing 6 mandatory constraints.   │
├───────────────────────────────┼────────────────────────────────────────┤
│ REST API                      │ Colloquial industry term for pragmatic │
│ (Pragmatic HTTP API)          │ JSON-over-HTTP APIs leveraging URIs    │
│                               │ and HTTP methods (Level 2 maturity).   │
├───────────────────────────────┼────────────────────────────────────────┤
│ RESTful API                   │ A web service that strictly fulfills   │
│ (Strict Conformance)          │ all 6 Fielding constraints, including  │
│                               │ hypermedia controls (Level 3 maturity).│
└───────────────────────────────┴────────────────────────────────────────┘

Understanding this distinction allows engineering teams to make intentional trade-offs between strict theoretical purity and pragmatic delivery when designing distributed backend systems and web applications.


2. Roy Fielding’s 2000 Dissertation: The Origin of REST

The acronym REST (Representational State Transfer) was coined by computer scientist Dr. Roy Thomas Fielding in Chapter 5 of his landmark 2000 doctoral dissertation at the University of California, Irvine, titled “Architectural Styles and the Design of Network-based Software Architectures.”

Fielding sought to document the architectural principles that made the World Wide Web exceptionally resilient, scalable, and capable of operating across distributed, heterogeneous networks without centralized coordination.

REST is neither a protocol, a language, nor a library. It is an architectural style—a coordinated set of architectural constraints applied to the components, connectors, and data elements within a distributed hypermedia system.


3. The Six Foundational Constraints of REST

To evaluate whether an API is genuinely RESTful, an architect must benchmark the system against Fielding’s six core architectural constraints. Violating any single mandatory constraint technically forfeits REST compliance.

                  ┌──────────────────────────────┐
                  │   Roy Fielding's 6 Rules     │
                  └──────────────┬───────────────┘
                                 │
         ┌───────────────┬───────┴───────┬───────────────┐
         ▼               ▼               ▼               ▼
   Client-Server    Statelessness   Cacheability   Layered System
         │               │               │               │
         └───────────────┼───────────────┴───────────────┘
                         │
         ┌───────────────┴───────────────┐
         ▼                               ▼
  Uniform Interface              Code on Demand
  - Resource ID                  (Optional)
  - Representations
  - Self-Descriptive
  - HATEOAS (Hypermedia)

1. Client-Server Separation

The user interface and user state concerns are decoupled from the data storage and business logic concerns. This separation allows frontend clients (web browsers, mobile applications, IoT devices) to evolve independently from server storage engines, enhancing cross-platform scalability.

2. Statelessness (RFC 9110)

Every request sent from the client to the server must contain all the contextual information, parameters, and authentication credentials required to process that request. The server must never store client session state in memory across requests. Statelessness dramatically improves server reliability and horizontal autoscaling because incoming requests can be routed to any available node behind a load balancer without sticky sessions.

3. Cacheability

To mitigate network latency and server overhead, data within a response must be implicitly or explicitly labeled as cacheable or non-cacheable. Utilizing standard HTTP headers (Cache-Control: max-age=3600, public, ETag, Last-Modified) allows intermediate proxies, CDNs, and client browsers to reuse existing responses for identical requests.

4. Layered System

A client cannot tell whether it is communicating directly with the origin server or with an intermediary. Intermediary layers—including reverse proxies, API Gateways, SSL terminators, rate limiters, and content delivery networks (CDNs)—can be inserted transparently without modifying client code, improving security and system scalability.

5. Uniform Interface

The Uniform Interface is the defining differentiator of REST. It simplifies the overall system architecture by enforcing four sub-constraints:

  • Identification of Resources: Individual resources are conceptualized and identified using discrete URIs (e.g., /api/v1/orders/7821).
  • Manipulation through Representations: Clients interact with resources through representations (e.g., JSON, XML) and hold sufficient metadata to modify or delete the underlying resource.
  • Self-Descriptive Messages: Each message includes standard media types (e.g., Content-Type: application/json) and HTTP status codes explaining how the client should parse and handle the response.
  • Hypermedia As The Engine Of Application State (HATEOAS): The client navigates application states entirely through hypermedia links provided dynamically inside resource representations, without relying on hardcoded client-side URI builders.

6. Code on Demand (Optional Constraint)

Servers may temporarily extend or customize client functionality by transferring executable logic, such as compiled WebAssembly binaries or JavaScript scripts. This is the only optional constraint in the REST architectural model.


4. The Richardson Maturity Model (RMM)

In 2008, software architect Leonard Richardson formulated the Richardson Maturity Model (RMM) (later popularized by Martin Fowler) to categorize web APIs according to their degree of REST conformance.

   Level 3: Hypermedia Controls (HATEOAS)    ◄── True "RESTful" API
      ▲
   Level 2: HTTP Verbs & Status Codes         ◄── 95% of Modern "REST APIs"
      ▲
   Level 1: Individual Resource URIs
      ▲
   Level 0: The Swamp of POX (Single URI/Method)

Level 0: The Swamp of Plain Old XML (POX)

At Level 0, the API uses HTTP merely as a raw tunneling transport mechanism. The entire application exposes a single endpoint URI (e.g., /rpc or /soap) and executes all operations using a single HTTP method (almost always POST). The payload contains internal RPC commands dispatching actions. Examples include XML-RPC, SOAP, and modern JSON-RPC.

POST /service HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
  "action": "cancelOrder",
  "orderId": 48102
}

Level 1: Individual Resource URIs

Level 1 introduces discrete URIs for separate business entities. Instead of funneling all operations through a single endpoint, the system allocates unique addresses: /orders, /orders/48102, and /users/91. However, Level 1 implementations often still misuse HTTP methods, using POST or GET indiscriminately for all mutations.

POST /orders/48102/cancel HTTP/1.1
Host: api.example.com

Level 2: Standard HTTP Verbs and Status Codes

Level 2 represents the modern industry standard for web services. Systems at this level strictly honor the semantics of HTTP methods defined in RFC 9110:

  • GET for safe, read-only data retrieval.
  • POST for creating subordinate resources or triggering non-idempotent processing.
  • PUT for complete resource replacement (idempotent).
  • PATCH for partial resource modifications.
  • DELETE for removing resources (idempotent).

Furthermore, Level 2 APIs return meaningful HTTP response codes: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Content, and 500 Internal Server Error.

Level 3: Hypermedia Controls (HATEOAS)

Level 3 is the pinnacle of the maturity model and the boundary of true RESTfulness. Responses deliver not just raw data attributes, but hypermedia controls (_links) indicating what state transitions are valid and reachable right now based on the resource’s current business state.


5. Architectural Comparison: REST API vs. RESTful API

The table below contrasts a standard pragmatic “REST API” (Level 2) with a strict “RESTful API” (Level 3):

Architectural DimensionPragmatic REST API (Level 2)Strict RESTful API (Level 3)
Primary Design FocusResource URIs + Standard HTTP VerbsHypermedia State Transitions & Uniform Interface
Maturity Level (RMM)Level 2 (HTTP Verbs & Status Codes)Level 3 (HATEOAS Hypermedia Controls)
Client NavigationClient hardcodes URI schemes based on OpenAPI specsClient discovers URIs dynamically from hypermedia links
Client-Server CouplingModerate: Breaking URI changes require client updatesLoose: URIs can change dynamically as long as link relations (rel) persist
Payload FormatPlain JSON (application/json)Hypermedia JSON (HAL application/hal+json, JSON:API, Siren)
DiscoverabilityOut-of-band documentation (Swagger, Redoc, Postman)Self-discoverable at runtime via root entry point (/api)
Industry Adoption~95% of public APIs (Stripe, GitHub, Twilio)~5% of specialized enterprise distributed architectures

6. Code Demonstration: Level 2 Pragmatic vs. Level 3 RESTful

To illustrate the technical divergence, consider an e-commerce order management system. An order can exist in different lifecycle states: pending_payment, paid, shipped, or cancelled.

Example 1: Pragmatic REST API (Level 2)

In a standard Level 2 API, requesting an order returns raw entity attributes:

GET /api/v1/orders/10842 HTTP/1.1
Host: api.store.com
Accept: application/json

Response (HTTP 200 OK):

{
  "id": 10842,
  "customer_id": 982,
  "status": "pending_payment",
  "total_amount": 149.50,
  "currency": "USD",
  "created_at": "2027-10-18T09:30:00Z"
}

The Architectural Limitation:
The client receives the data, but has no runtime indication of what actions are legally permissible. To cancel or pay for this order, the client must consult external developer documentation, hardcode the path /api/v1/orders/10842/payment, and implement client-side conditional checks (if status === 'pending_payment'). If backend engineers alter the cancellation URI scheme, client applications break.


Example 2: Strict RESTful API with HATEOAS (Level 3 HAL Standard)

In a Level 3 RESTful API conforming to the HAL (Hypertext Application Language) standard (application/hal+json), the server conveys both resource data and actionable state affordances:

GET /api/v1/orders/10842 HTTP/1.1
Host: api.store.com
Accept: application/hal+json

Response (HTTP 200 OK):

{
  "id": 10842,
  "customer_id": 982,
  "status": "pending_payment",
  "total_amount": 149.50,
  "currency": "USD",
  "created_at": "2027-10-18T09:30:00Z",
  "_links": {
    "self": {
      "href": "/api/v1/orders/10842",
      "method": "GET"
    },
    "customer": {
      "href": "/api/v1/customers/982",
      "method": "GET"
    },
    "payment": {
      "href": "/api/v1/orders/10842/transactions",
      "method": "POST",
      "title": "Submit payment for this order"
    },
    "cancel": {
      "href": "/api/v1/orders/10842/cancellation",
      "method": "PUT",
      "title": "Cancel order before fulfillment"
    }
  }
}

Now consider what happens once the customer pays for the order:

POST /api/v1/orders/10842/transactions HTTP/1.1
Host: api.store.com
Content-Type: application/json

{
  "payment_method_token": "pm_tok_visa_4242"
}

Response (HTTP 200 OK):

{
  "id": 10842,
  "customer_id": 982,
  "status": "paid",
  "total_amount": 149.50,
  "currency": "USD",
  "paid_at": "2027-10-18T09:32:15Z",
  "_links": {
    "self": {
      "href": "/api/v1/orders/10842",
      "method": "GET"
    },
    "receipt": {
      "href": "/api/v1/orders/10842/receipt.pdf",
      "method": "GET"
    },
    "tracking": {
      "href": "/api/v1/orders/10842/shipment",
      "method": "GET"
    }
  }
}

Notice that the "payment" and "cancel" links have dynamically disappeared from _links, replaced by "receipt" and "tracking". The client does not need hardcoded business rules; it simply inspects whether the "cancel" link relation exists before rendering a “Cancel Order” button in the user interface.


7. Production Implementation: Building a RESTful Controller

Below is an enterprise TypeScript implementation demonstrating a state-driven RESTful controller with dynamic hypermedia links:

// src/controllers/OrderController.ts
import { Request, Response } from 'express';

interface OrderEntity {
  id: string;
  customerId: string;
  status: 'pending_payment' | 'paid' | 'shipped' | 'cancelled';
  totalAmount: number;
}

interface HalLink {
  href: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  title?: string;
}

export class OrderController {
  public async getOrder(req: Request, res: Response): Promise<void> {
    const { orderId } = req.params;
    
    // Retrieve entity from repository
    const order: OrderEntity | null = await this.findOrderInDatabase(orderId);
    
    if (!order) {
      res.status(404).json({
        type: 'https://api.store.com/errors/not-found',
        title: 'Resource Not Found',
        status: 404,
        detail: `Order with identifier ${orderId} does not exist.`
      });
      return;
    }

    // Build dynamic HATEOAS link affordances based on current state
    const links: Record<string, HalLink> = {
      self: { href: `/api/v1/orders/${order.id}`, method: 'GET' },
      customer: { href: `/api/v1/customers/${order.customerId}`, method: 'GET' }
    };

    if (order.status === 'pending_payment') {
      links.payment = {
        href: `/api/v1/orders/${order.id}/transactions`,
        method: 'POST',
        title: 'Submit payment'
      };
      links.cancel = {
        href: `/api/v1/orders/${order.id}/cancellation`,
        method: 'PUT',
        title: 'Cancel pending order'
      };
    } else if (order.status === 'paid') {
      links.receipt = {
        href: `/api/v1/orders/${order.id}/receipt`,
        method: 'GET',
        title: 'Download tax invoice'
      };
    }

    // Return hypermedia representation with explicit media type
    res.setHeader('Content-Type', 'application/hal+json');
    res.setHeader('Cache-Control', 'private, max-age=60');
    
    res.status(200).json({
      id: order.id,
      customerId: order.customerId,
      status: order.status,
      totalAmount: order.totalAmount,
      _links: links
    });
  }

  private async findOrderInDatabase(id: string): Promise<OrderEntity | null> {
    // Database lookup simulation
    return {
      id,
      customerId: 'cust_8829',
      status: 'pending_payment',
      totalAmount: 249.99
    };
  }
}

8. HTTP Method Semantics: Safety and Idempotency (RFC 9110)

Architecting reliable distributed systems requires strict compliance with HTTP method semantics. Developers frequently confuse Safety with Idempotency:

┌───────────┬───────────────┬───────────────────┬────────────────────────┐
│ Method    │ Safe?         │ Idempotent?       │ Primary Semantics      │
├───────────┼───────────────┼───────────────────┼────────────────────────┤
│ GET       │ Yes (Read)    │ Yes               │ Retrieve representation│
│ HEAD      │ Yes (Read)    │ Yes               │ Headers only (no body) │
│ OPTIONS   │ Yes (Read)    │ Yes               │ Query supported methods│
│ PUT       │ No (Mutates)  │ Yes (Full Replace)│ Replace target resource│
│ DELETE    │ No (Mutates)  │ Yes (Removal)     │ Remove target resource │
│ POST      │ No (Mutates)  │ No (New resource) │ Subordinate processing │
│ PATCH     │ No (Mutates)  │ No / Conditional  │ Partial modification   │
└───────────┴───────────────┴───────────────────┴────────────────────────┘
  • Safe Methods: Methods that do not alter server resource state (GET, HEAD, OPTIONS). Clients can call safe methods repeatedly, pre-fetch them, or parallelize requests without side effects.
  • Idempotent Methods: Methods where the intended effect on server state of multiple identical requests is identical to the effect of a single request. If a network timeout occurs during a PUT or DELETE request, the client can safely retry the request without creating duplicate records or corruption.
  • Non-Idempotent Methods: POST is inherently non-idempotent. Retrying a POST /orders request on a network disconnect could result in double-charging a customer or duplicating records. Enterprise APIs resolve this using unique Idempotency-Key request headers.

9. Why 95% of the Industry Remains at Level 2

If Level 3 HATEOAS represents the pinnacle of RESTfulness, why do industry leaders like Stripe, Shopify, GitHub, and AWS build Level 2 APIs instead of Level 3?

  1. Payload Bloat & Mobile Bandwidth: Adding verbose _links objects to every collection item dramatically increases JSON payload sizes, introducing measurable latency on mobile networks.
  2. The Rise of Strongly Typed Client SDKs: Modern engineering teams prioritize end-to-end type safety. Tools like TypeScript, OpenAPI (Swagger), and GraphQL allow engineers to generate static, type-safe API clients at compile time. Dynamic runtime hypermedia links run counter to static typing workflows.
  3. Frontend Routing Paradigms: Single Page Applications (React, Vue, Astro) handle client-side routing, navigation guards, and UI permissions internally. Parsing dynamic link affordances from every API response introduces redundant client-side orchestration.
  4. Developer Experience (DX): Level 2 APIs are intuitive, predictable, and easy to consume with standard curl or fetch commands without traversing discovery graphs.

10. When Should You Build a True Level 3 RESTful API?

While Level 2 suffices for 95% of web applications, strict Level 3 RESTful architecture is uniquely advantageous in specific enterprise environments:

  • Long-Lived Distributed Systems with Autonomous Clients: When third-party client integrations must operate for decades without breaking, HATEOAS allows servers to evolve endpoints, deprecate routes, and alter workflows without requiring client recompilation.
  • Complex Multi-Step Finite State Machines: For enterprise workflows (e.g., loan approvals, international logistics, medical insurance claims) where legal state transitions change based on role, time, and compliance rules, server-driven hypermedia links centralize business rules on the server.
  • Media-Agnostic Engine Architectures: When diverse clients (IoT hardware, command-line interfaces, web portals, voice assistants) must navigate backend capabilities without custom client-side business logic.

Frequently Asked Questions

What is the core difference between a REST API and a RESTful API?

In formal computer science, REST (Representational State Transfer) is the architectural pattern and set of six theoretical constraints defined by Roy Fielding in 2000. A RESTful API is a concrete implementation that strictly adheres to all six constraints—most notably the Uniform Interface constraint including HATEOAS (Hypermedia As The Engine Of Application State). In daily developer parlance, however, the terms are frequently used interchangeably to describe JSON-over-HTTP endpoints.

What is the Richardson Maturity Model, and which level represents a true RESTful API?

The Richardson Maturity Model divides API architecture into four tiers: Level 0 (single URI and method like XML-RPC/SOAP), Level 1 (individual resource URIs), Level 2 (standard HTTP verbs and status codes), and Level 3 (hypermedia controls / HATEOAS). While 95% of production web APIs operate comfortably at Level 2, only Level 3 implementations that provide dynamic hypermedia links meet Roy Fielding's strict definition of a RESTful system.

Why do most modern web APIs omit HATEOAS?

Most production APIs skip HATEOAS because of developer overhead, network payload bloat, and the widespread adoption of static contract tools like OpenAPI (Swagger) and TypeScript schemas. Frontend and mobile teams generally prefer compile-time type safety and strongly typed client SDKs over dynamically parsing runtime hypermedia link affordances.

Is a REST API always bound to the HTTP protocol?

Theoretically, REST is a network architectural style that is protocol-agnostic; it can operate over any protocol that supports a uniform interface and hierarchical resource identification. In practice, however, virtually every REST and RESTful API relies on HTTP/1.1, HTTP/2, or HTTP/3 because HTTP natively implements client-server separation, caching headers, status codes, and uniform verbs (GET, POST, PUT, DELETE).

What does idempotency mean in REST API design?

An HTTP method is idempotent if executing multiple identical requests produces the exact same server resource state as executing a single request. Under RFC 9110, GET, HEAD, PUT, DELETE, and OPTIONS are idempotent. POST is non-idempotent because repeatedly sending a creation request creates multiple distinct resources unless guarded by idempotency keys.


Elevate Your Enterprise API Architecture

Designing mission-critical distributed systems requires pragmatic engineering balance. Discover how our Laravel Backend Architecture Services and Modern Web Development Engineering help high-growth teams build resilient, scalable APIs.

Schedule an Architecture Consultation

Share:
Back to Blog

Related Posts

View All Posts »