RESTful API Development

Chapter 2
REST Architectural Style

Bachelors Program in Full Stack Development
RESTful API Development   •   Bachelor

REST Architectural Style

Introduction

The Representational State Transfer (REST) architectural style provides a set of constraints for designing distributed information systems. It was introduced by Roy Fielding in his doctoral dissertation as an architectural model for the World Wide Web, not as a programming library or a wire protocol. REST explains why the web can scale across millions of clients, servers, intermediaries, and independently developed applications.

A RESTful API exposes resources through representations exchanged using a standardized interface, commonly HTTP. For example, an online learning platform may expose courses, students, enrolments, and assessments as resources. A client requests a representation of a resource, such as a JSON document describing a course, rather than calling a server-side procedure such as getCourseDetails().

REST is important in full-stack development because it influences URL design, HTTP method selection, caching, security, fault handling, scalability, and the division of responsibilities between front-end and back-end systems. However, merely using HTTP and JSON does not automatically make an API RESTful. RESTfulness depends on adherence to architectural constraints.

Learning Objectives

By the end of this chapter, you should be able to:

  • explain the six principal REST constraints;
  • distinguish resources, representations, identifiers, and state;
  • analyze how REST constraints support scalability and evolvability;
  • explain safe, idempotent, and cacheable HTTP operations;
  • compare RESTful design with remote procedure call (RPC) design;
  • distinguish Richardson’s Maturity Model levels;
  • identify practical, governance, and security implications of RESTful APIs.

1. REST as an Architectural Style

An architectural style is a set of principles that guides the organization of software components and their interactions. It is less prescriptive than a framework and more general than an implementation technique. REST therefore does not require a particular programming language, database, server, or serialization format.

The central abstraction in REST is the resource. A resource is any concept that can be named and accessed: a user, invoice, product, image, search result, or collection of messages. A resource is identified by a URI, such as:

https://api.example.edu/courses/42

The URI identifies the course resource; it does not necessarily reveal how that resource is stored. The server may store the course in a relational database, document store, cache, or several systems simultaneously.

A representation is a transferable description of the current or intended state of a resource. The same course might be represented as JSON, XML, HTML, or CSV depending on the request and server capabilities. The resource and its representation are therefore related but not identical.

A useful distinction is:

  • Resource: the conceptual object or information being addressed.
  • Identifier: the URI used to refer to it.
  • Representation: a document transferred between client and server.
  • Resource state: information maintained by the server about the resource.
  • Application state: the client’s position in an interaction, such as which link it follows next.

REST uses the uniform semantics of HTTP methods to manipulate resources. A client does not normally need to know the server’s internal function names or database schema.

REST interaction among client, intermediaries, and server Clientapplication state Intermediariescache, gateway,load balancer Serverresource state HTTP requestHTTP request representationrepresentation
REST interaction among client, intermediaries, and server
Figure: REST interaction among client, intermediaries, and server

Figure: A REST interaction can include intermediaries without requiring the client to know the server’s internal structure.

2. The REST Constraints

Fielding described REST through a sequence of constraints. Each constraint addresses a design problem in distributed systems. The constraints are cumulative: a system that applies later constraints but violates an earlier one may use HTTP effectively, yet it is not fully RESTful.

2.1 Client–Server Separation

The client and server have distinct responsibilities. The client is responsible for the user interface and user experience; the server is responsible for data storage, business rules, and resource management. They communicate through a defined interface.

This separation allows each side to evolve independently. A mobile application, browser application, and command-line client can use the same API. Likewise, a server can change its database technology without requiring clients to understand the change.

Separation does not mean that clients and servers have no dependencies. They still depend on agreed resource identifiers, representations, status codes, authentication mechanisms, and media types. The objective is to reduce unnecessary coupling, not to eliminate all contracts.

2.2 Statelessness

Each request must contain all information necessary for the server to understand and process it. The server must not rely on stored conversational context from previous requests.

For example, a request might include an access token, resource URI, query parameters, and representation. A later request should not require the server to remember that the client previously visited a particular page or selected a particular account.

Statelessness improves horizontal scalability. Any server instance can process any request, which simplifies load balancing, failover, and recovery. It also makes failures easier to reason about because a request can be retried or routed to another instance without reconstructing a server-side session.

Statelessness does not prohibit all server-side data. Servers must store resource state, user accounts, audit records, and other durable information. The constraint prohibits server-side storage of client-specific conversational state needed to interpret the next request.

A common misconception is that token authentication automatically makes a system stateless. If a token is self-contained and independently verifiable, it can support stateless processing. If the server must consult a session store for every token, the system may still be operationally stateful, although it can remain compatible with many REST principles.

2.3 Cacheability

Responses must explicitly or implicitly indicate whether they are cacheable. A cache stores a response and reuses it for later requests when the response remains valid.

HTTP provides cache-control mechanisms such as Cache-Control, ETag, Last-Modified, and Expires. For example, a public course catalogue that changes infrequently may be cacheable for a short period. A private banking balance may require restrictive caching rules.

Caching reduces latency, bandwidth consumption, and server workload. It can also create risks: stale data, privacy leakage, incorrect invalidation, and inconsistent views. Developers must therefore specify cache behavior rather than assuming that every response should be cached.

An ETag is a validator identifying a particular representation. A client can send If-None-Match with that value. If the representation has not changed, the server may return 304 Not Modified without retransmitting the body. This is different from blindly serving a cached response: the server validates whether the cached representation is still current.

2.4 Uniform Interface

The uniform interface is the defining REST constraint. It reduces coupling by requiring communication to use standardized, general-purpose semantics rather than application-specific commands.

It includes four related principles:

  1. Identification of resources: resources are identified independently of their representations.
  2. Manipulation through representations: a client with a suitable representation and permission can request a change to a resource.
  3. Self-descriptive messages: messages contain enough information to interpret them, including media type, status, and relevant metadata.
  4. Hypermedia as the engine of application state (HATEOAS): representations may provide links or controls that guide the client’s next actions.

For example, a response to GET /orders/81 may include links to cancel, pay, or view shipment details, depending on the order’s current state and the client’s permissions. The client follows available controls instead of constructing every possible URI from undocumented assumptions.

In practice, many APIs use resource-oriented URLs and standard HTTP methods but provide few hypermedia controls. Such APIs can be useful and well designed, but they do not fully implement the strongest interpretation of HATEOAS.

2.5 Layered System

A client cannot ordinarily tell whether it is connected directly to the origin server or through a proxy, gateway, cache, authentication service, or load balancer. Each layer offers services to the next layer while limiting visibility of the overall system.

Layering improves scalability, security, and manageability. A gateway can enforce rate limits; a cache can serve common responses; a reverse proxy can terminate TLS; and a service mesh can provide observability. Because layers should communicate through the same interface, infrastructure can be changed without redesigning the client.

Layering can also introduce complexity. Debugging requires correlation identifiers and distributed tracing. Incorrect proxy configuration can affect authentication, caching, compression, or routing. The architectural benefit therefore depends on clear contracts and operational discipline.

2.6 Code-on-Demand (Optional)

Code-on-demand allows a server to transfer executable code to a client, extending the client’s functionality. JavaScript delivered by a web server is a familiar example.

This constraint is optional because executable code can increase flexibility but also creates security, performance, portability, and governance concerns. A client must trust the source and control what code is permitted to execute. Most API discussions focus on the other five constraints, while code-on-demand is more relevant to browser-based web systems than to ordinary server-to-server APIs.

3. HTTP Semantics in RESTful Design

RESTful design uses HTTP semantics consistently rather than treating HTTP as a tunnel for arbitrary commands.

MethodTypical useSafe?Idempotent?
GETRetrieve a representationYesYes
HEADRetrieve headers onlyYesYes
POSTCreate subordinate resource or process a submissionNoNo, generally
PUTReplace or create a resource at a known URINoYes
PATCHPartially modify a resourceNo, generallyDepends on operation
DELETERemove a resourceNoYes

A safe method is intended only for retrieval and should not request a state change. Safe does not mean risk-free: a GET may cause logging or accounting effects, but those are not the requested semantic purpose.

An idempotent method has the property that making the same request once or multiple times has the same intended effect as making it once. If PUT /profiles/7 stores the same complete representation repeatedly, the final resource state is the same. Idempotence does not guarantee identical response metadata, timestamps, or logs.

A method’s idempotence is a semantic property, not merely a feature of a particular implementation. POST /payments generally creates a new payment attempt each time. An idempotency key can help prevent accidental duplication, but it does not turn every POST into PUT.

Status codes communicate results. Common examples include 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 412 Precondition Failed, 429 Too Many Requests, and 500 Internal Server Error. Correct status selection improves interoperability and client error handling.

4. REST Maturity and the Richardson Model

The Richardson Maturity Model is a practical classification of API design. It is not Fielding’s formal definition of REST, and reaching Level 3 does not automatically prove that every REST constraint has been satisfied.

LevelMain characteristicExample
0One endpoint and one transport mechanismPOST /api with operation names in the body
1Resource-oriented URIs/customers/7, /orders/81
2HTTP verbs and status codes used appropriatelyGET, POST, PUT, DELETE with meaningful responses
3Hypermedia controls guide available transitionsResponse contains links such as cancel or pay

Level 0 resembles an RPC tunnel. Level 1 introduces resources but may still misuse HTTP methods. Level 2 uses HTTP semantics as part of the application contract. Level 3 adds discoverability and state transitions through hypermedia.

The model is useful for assessment and incremental improvement, but it should not become a simplistic scorecard. An API may have excellent resource modeling, caching, security, and documentation while using limited hypermedia. Architectural quality must be judged against the system’s requirements.

5. RESTful Design Compared with RPC

RPC models interaction as invocation of a remote procedure. The client asks the server to execute an operation, often naming a method such as calculateShipping, approveInvoice, or getUser. REST models interaction around resources and standardized representations.

DimensionREST-oriented designRPC-oriented design
Primary abstractionResourceProcedure or action
InterfaceUniform and standardizedOperation-specific
Typical requestPOST /ordersPOST /createOrder or createOrder()
State transitionsHTTP methods and representationsExplicit commands
Intermediary supportStrong use of HTTP caches and proxiesOften requires operation-specific knowledge
CouplingUsually lower semantic couplingOften tighter coupling to method contracts
Best fitCRUD, public APIs, resource networksComplex commands, internal services, action-heavy workflows

The distinction is not absolute. A REST API may expose an action as a subordinate resource, such as POST /orders/81/cancellations, when cancellation is a meaningful business resource. Conversely, an RPC service may use HTTP and JSON without being RESTful.

REST is not automatically superior. RPC can be clearer for operations that do not map naturally to resource manipulation, such as initiating a long-running computation or executing a domain-specific command. The important design question is whether the chosen abstraction supports clear contracts, evolvability, observability, and appropriate coupling.

6. Worked Design Example: University Course Registration

Consider an API for course registration. A weak RPC-style interface might expose:

  • POST /api with { "operation": "registerStudent", "studentId": 12, "courseId": 42 };
  • POST /api with { "operation": "dropStudent", ... };
  • POST /api with { "operation": "listCourses" }.

The server must parse operation names and define special rules for every command. Caches, generic clients, and monitoring tools have little semantic information.

A more resource-oriented design could use:

  • GET /courses to retrieve courses;
  • GET /courses/42 to retrieve one course;
  • GET /students/12/enrolments to retrieve a student’s enrolments;
  • POST /students/12/enrolments to create an enrolment;
  • DELETE /students/12/enrolments/9001 to remove a particular enrolment.

A successful creation may return 201 Created, a Location header identifying the new enrolment, and a representation of that enrolment. If the course is full, 409 Conflict can communicate that the request conflicts with current resource state. If authentication is valid but the student lacks permission, 403 Forbidden is more appropriate than 404 Not Found, subject to the institution’s information-disclosure policy.

A representation might include:

{
  "id": 9001,
  "student": "/students/12",
  "course": "/courses/42",
  "status": "confirmed",
  "links": [
    { "rel": "course", "href": "/courses/42" },
    { "rel": "drop", "href": "/students/12/enrolments/9001", "method": "DELETE" }
  ]
}

The links express available relationships and, potentially, transitions. A student whose enrolment is pending might receive a cancel link rather than a drop link. This allows the server to communicate permitted actions based on current state, policy, and role.

The design still requires careful decisions. Registration is often subject to concurrency constraints: two clients may attempt to claim the final seat. Conditional requests, transactions, and a conflict response can help preserve consistency. REST does not remove domain complexity; it provides a disciplined communication style for exposing that complexity.

7. Applied Case: Illustrative Public Transport API

Background

A regional transport authority operates buses and trains. Its original mobile application uses a single endpoint, /service, with commands embedded in JSON. During peak periods, response times increase and a new third-party journey-planning application is difficult to integrate.

Problem

The existing interface has tightly coupled operation names, inconsistent error responses, no reliable caching policy, and server-side sessions that make horizontal scaling difficult. A failure in one application server can invalidate users’ conversational sessions.

Analysis

The authority identifies relatively stable resources: stops, routes, journeys, vehicle positions, and service alerts. Real-time vehicle positions change frequently, whereas route descriptions change infrequently. This difference suggests resource-specific cache policies. The team also separates authentication from conversational workflow so that each request carries the credentials and parameters required for processing.

Approach and solution

The redesigned API uses endpoints such as:

  • GET /stops/{id};
  • GET /routes/{id};
  • GET /vehicle-positions?route=R4;
  • GET /alerts;
  • POST /journey-plans for submitting a journey-planning request.

Responses use standard status codes and media types. Route descriptions receive cache validators and longer freshness periods. Vehicle-position responses receive short freshness periods because stale data can mislead passengers. A gateway performs rate limiting, while a cache handles frequently requested route data. Correlation IDs support tracing across gateway and service layers.

The API does not pretend that every operation is simple CRUD. Journey planning is modeled as the creation of a planning request because it may involve computation and produce a result resource. A response can return 202 Accepted with a URI for checking the result if processing is asynchronous.

Outcome

The new design allows independent mobile and web clients, improves cache utilization for stable resources, and permits additional application servers to be added without copying user sessions. Third parties can understand the basic interface using HTTP documentation and representations rather than learning a single proprietary command protocol.

Learning points

The case demonstrates that REST constraints are architectural trade-offs, not cosmetic URL rules. Stateless requests, meaningful caching, standardized semantics, and layered infrastructure work together. The design also shows that RESTful modeling can accommodate both ordinary resources and long-running domain operations.

8. Challenges, Governance, and Security

REST does not solve authentication or authorization by itself. APIs must protect confidentiality, integrity, and availability through TLS, secure credential handling, least privilege, input validation, and appropriate authorization checks. A URI should not be treated as proof that a client is allowed to access the identified resource.

Privacy affects caching and representations. Responses containing personal, financial, educational, or health information require restrictive cache directives and careful logging. Logs should avoid unnecessary tokens and sensitive payloads. Error messages should provide useful diagnostic information without disclosing confidential data.

Versioning presents a governance challenge. URI versioning, media-type versioning, and backward-compatible evolution each have advantages. Teams should prefer additive changes, tolerate unknown fields where appropriate, document deprecation periods, and monitor actual client usage before removing capabilities.

Other practical risks include:

  • over-fetching or under-fetching data;
  • inconsistent pagination and filtering conventions;
  • accidental non-idempotence in retryable operations;
  • cache invalidation errors;
  • excessively chatty client interactions;
  • undocumented coupling to URI structures;
  • denial-of-service through expensive queries;
  • insecure direct object references;
  • inconsistent error formats.

OpenAPI and similar contract-description tools can document endpoints, schemas, parameters, and responses. They improve collaboration but do not establish RESTfulness by themselves. Automated contract tests, security tests, consumer-driven tests, observability, and performance testing are equally important.

AI-assisted development can generate endpoint scaffolding, schemas, and test cases, but generated code must be reviewed for authorization flaws, unsafe deserialization, incorrect HTTP semantics, sensitive-data exposure, and invented assumptions about domain rules. Human oversight remains essential because architectural correctness depends on context.

9. Best Practices for RESTful API Design

  1. Model stable domain concepts as resources and choose identifiers that remain understandable.
  2. Use HTTP methods and status codes according to their standardized semantics.
  3. Make requests self-contained and avoid unnecessary conversational server state.
  4. Define cache behavior explicitly, especially for private or rapidly changing data.
  5. Use representations that are self-descriptive and document media types and schemas.
  6. Design for evolution through additive changes, compatibility policies, and deprecation.
  7. Treat authorization as a resource-level decision, not merely an endpoint-level decision.
  8. Use conditional requests and idempotency strategies where retries can cause harm.
  9. Provide consistent error representations, pagination, filtering, and validation rules.
  10. Use gateways and other intermediaries deliberately, with tracing and clear ownership.
  11. Add hypermedia where discoverability and dynamic state transitions provide real value.
  12. Test behavior, not only URL syntax: caching, retries, concurrency, failure, and security matter.

Chapter Summary

REST is an architectural style for distributed systems based on resources, representations, and a uniform interface. Its principal constraints are client–server separation, statelessness, cacheability, a uniform interface, layered systems, and optional code-on-demand. Together they support independent evolution, scalability, intermediary participation, and improved interoperability.

A resource is identified by a URI and transferred through representations. HTTP methods provide standardized semantics: GET is safe and idempotent, PUT and DELETE are idempotent, and POST is generally neither safe nor idempotent. Cache validators and explicit cache controls can reduce latency while limiting staleness and privacy risks.

The Richardson Maturity Model describes a progression from a single RPC-like endpoint to resource-oriented URIs, appropriate HTTP semantics, and hypermedia controls. It is a practical classification rather than the formal definition of REST. REST and RPC represent different abstractions: REST centers on resources and uniform semantics, whereas RPC centers on named procedures. Neither is universally best; the choice should reflect domain operations and system constraints.

Effective RESTful API engineering requires more than URL conventions. It includes security, authorization, governance, observability, compatibility, concurrency control, and careful treatment of caching and errors.

Key Terms

Resource: A conceptual object or information unit that can be identified and addressed.

Representation: A transferable description of a resource’s state.

URI: A uniform identifier used to identify a resource.

Client–server separation: Division of interface responsibilities between client and server.

Statelessness: Requirement that each request contain the information necessary for processing.

Cacheability: Ability to reuse a response according to declared freshness and validation rules.

Uniform interface: Standardized interaction constraints that reduce coupling between components.

HATEOAS: Hypermedia as the engine of application state; using links or controls to guide transitions.

Layered system: Architecture in which intermediaries provide services while hiding internal structure.

Code-on-demand: Optional transfer of executable code from server to client.

Safe method: HTTP method intended not to request a state change.

Idempotent method: Method whose repeated application has the same intended effect as one application.

Representation state: Information about a resource transferred in a representation.

Application state: Client’s position or progress in an interaction.

RPC: Remote procedure call, an operation-oriented communication style.

HTTP status code: Standard response code describing the result of an HTTP request.

ETag: Representation validator used for cache validation and conditional requests.

Richardson Maturity Model: Classification of APIs from Level 0 to Level 3 according to REST-related practices.

Intermediary: Component such as a proxy, cache, gateway, or load balancer between client and origin server.

Idempotency key: Client-supplied value used to prevent duplicate effects when retrying selected operations.

Review Questions

Short Answer Questions

  1. What is the difference between a resource and a representation?
  2. Why does statelessness support horizontal scaling?
  3. Define a safe HTTP method and give one example.
  4. What is the purpose of an ETag?
  5. What distinguishes Level 2 from Level 3 in the Richardson Maturity Model?

Long Answer Questions

  1. Explain all six REST constraints and discuss how each contributes to a scalable web architecture.
  2. Compare REST and RPC with reference to abstraction, coupling, intermediaries, and error handling.
  3. Explain the four principles commonly associated with the uniform interface constraint.
  4. Discuss the benefits and risks of caching in a RESTful API.
  5. Explain why using HTTP and JSON does not, by itself, make an API RESTful.

Analytical / Application Questions

  1. Design a REST-oriented interface for library loans. Identify resources, URIs, methods, likely status codes, and one useful hypermedia control.
  2. An API uses POST /api for every operation and stores user workflow state in server memory. Analyze which REST constraints are weakened and propose improvements.
  3. A client retries a payment request after a network timeout. Explain the risks of retrying POST, and design an approach using resource modeling and/or idempotency controls.

Multiple Choice Questions with Answers

Question 1

Which REST constraint requires each request to contain the information needed for the server to process it?

A. Layered system

B. Statelessness

C. Code-on-demand

D. Cacheability

Correct Answer: B. Statelessness

Question 2

What is the primary abstraction in REST?

A. Database table

B. Remote procedure

C. Resource

D. Programming thread

Correct Answer: C. Resource

Question 3

Which HTTP method is generally both safe and idempotent?

A. POST

B. PATCH

C. GET

D. CONNECT

Correct Answer: C. GET

Question 4

What does an ETag primarily support?

A. Encryption of credentials

B. Cache validation

C. Database normalization

D. User interface rendering

Correct Answer: B. Cache validation

Question 5

Which Richardson Maturity Model level introduces appropriate HTTP verbs and status codes?

A. Level 0

B. Level 1

C. Level 2

D. Level 3

Correct Answer: C. Level 2

Question 6

Which example best represents an RPC-style interface?

A. GET /courses/42

B. DELETE /orders/81

C. POST /api with operation 'calculateFare'

D. GET /students/12/enrolments

Correct Answer: C. POST /api with operation 'calculateFare'

Question 7

Why can a layered REST system improve scalability?

A. It prevents all failures from occurring

B. It allows intermediaries such as caches and gateways to provide specialized services

C. It requires every client to know the database schema

D. It eliminates the need for HTTP status codes

Correct Answer: B. It allows intermediaries such as caches and gateways to provide specialized services

Question 8

Which statement about PUT is generally correct?

A. It is always unsafe and non-idempotent

B. It is normally used to retrieve a representation

C. Repeated identical PUT requests have the same intended final effect

D. It can only be used for authentication

Correct Answer: C. Repeated identical PUT requests have the same intended final effect

Question 9

What is HATEOAS intended to provide?

A. A database backup mechanism

B. Hypermedia controls that guide available application transitions

C. A replacement for TLS

D. A mandatory binary serialization format

Correct Answer: B. Hypermedia controls that guide available application transitions

Question 10

A response contains private student records. Which design concern is most directly relevant to caching?

A. Whether the response may be stored or reused without exposing confidential data

B. Whether the URI contains a verb

C. Whether the server uses relational tables

D. Whether the client uses JavaScript

Correct Answer: A. Whether the response may be stored or reused without exposing confidential data

RESTful API Development
Chapter 2 of 15