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
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:
Identification of resources: resources are identified independently of their representations.
Manipulation through representations: a client with a suitable representation and permission can request a change to a resource.
Self-descriptive messages: messages contain enough information to interpret them, including media type, status, and relevant metadata.
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.
Method
Typical use
Safe?
Idempotent?
GET
Retrieve a representation
Yes
Yes
HEAD
Retrieve headers only
Yes
Yes
POST
Create subordinate resource or process a submission
No
No, generally
PUT
Replace or create a resource at a known URI
No
Yes
PATCH
Partially modify a resource
No, generally
Depends on operation
DELETE
Remove a resource
No
Yes
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.
Level
Main characteristic
Example
0
One endpoint and one transport mechanism
POST /api with operation names in the body
1
Resource-oriented URIs
/customers/7, /orders/81
2
HTTP verbs and status codes used appropriately
GET, POST, PUT, DELETE with meaningful responses
3
Hypermedia controls guide available transitions
Response 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.
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.
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
Model stable domain concepts as resources and choose identifiers that remain understandable.
Use HTTP methods and status codes according to their standardized semantics.
Make requests self-contained and avoid unnecessary conversational server state.
Define cache behavior explicitly, especially for private or rapidly changing data.
Use representations that are self-descriptive and document media types and schemas.
Design for evolution through additive changes, compatibility policies, and deprecation.
Treat authorization as a resource-level decision, not merely an endpoint-level decision.
Use conditional requests and idempotency strategies where retries can cause harm.
Provide consistent error representations, pagination, filtering, and validation rules.
Use gateways and other intermediaries deliberately, with tracing and clear ownership.
Add hypermedia where discoverability and dynamic state transitions provide real value.
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
What is the difference between a resource and a representation?
Why does statelessness support horizontal scaling?
Define a safe HTTP method and give one example.
What is the purpose of an ETag?
What distinguishes Level 2 from Level 3 in the Richardson Maturity Model?
Long Answer Questions
Explain all six REST constraints and discuss how each contributes to a scalable web architecture.
Compare REST and RPC with reference to abstraction, coupling, intermediaries, and error handling.
Explain the four principles commonly associated with the uniform interface constraint.
Discuss the benefits and risks of caching in a RESTful API.
Explain why using HTTP and JSON does not, by itself, make an API RESTful.
Analytical / Application Questions
Design a REST-oriented interface for library loans. Identify resources, URIs, methods, likely status codes, and one useful hypermedia control.
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.
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