Selecione um idioma
“A [person] thinks that by mouthing hard words he or she understands hard things.” - Herman Melville
How many times have you met with a team of engineers, architects, or even clients to talk about the designs of a software feature, and a single word used caused mass confusion because everyone had a slightly different definition? (Ugh, why are words so hard?!)
I have never found a more challenging concept to talk about than Representational State Transfer (REST). What does REST and being RESTful mean? Are resources the same thing as entities? Where do representations come into the mix? This blog post will answer these questions and describe the RESTful architectural style.
Putting this Confusion to REST
Representational State Transfer, or REST for short, is an architectural style created by Roy Fielding as part of his dissertation in the year 2000. The goal was to describe a set of engineering principles and interaction constraints for designing distributed information systems. A RESTful system adheres to the constraints of a REST architectural style. For example, creating a web-based API adhering to these constraints is considered a “RESTful” web API. Just because you do not have a RESTful API doesn’t mean it isn’t useful; you might not reap the benefits promised by the architecture.
Fielding’s dissertation identified six constraints (one is optional) to designing a RESTful system. The combination of all these rules reduces the complexities of creating a distributed system. When we’re not adhering to all of these constraints, we risk creating additional issues to our system’s design.
Let’s discuss each constraint and how to work with the tradeoffs.
The client-server model has been around since the dinosaurs. It’s all about the separation of concerns. We want concerns of the client to be able to change and evolve without having to change anything on the server. I should also be able to change various aspects of the server without breaking clients.
Ultimately, this is about how the client sends the server a message, and how the server rejects or responds to the client.
State is one of those aspects of software engineering that often causes trouble. The communication between the client and the server must remain stateless between requests. Each request the client makes should contain all information needed for the server to answer successfully. All of the state information should be transferred back to the client as part of the response. This is the “S” and “T” in REST; we are always giving the state back to the client.
Unfortunately, making this interaction stateless does have some consequences. For example, being able to store state on the server could help with performance. To address the performance of a stateless system, several constraints were added.
Whenever a server responds to a client’s request, the server should be able to mark that response as something the client can cache or something that should not be cached. Any component between the client and server could also cache the response. This will help with any negative impacts from having stateless interactions as well as increase the user’s perceived performance.
Layered System Constraint
Messages between a client and server can go through any number of intermediaries. This could be load balancers, proxy servers, firewalls, or other types of devices. Each component should not be able to “see” the next layer. The interaction between the client and server should not be affected by these devices. All communication should remain consistent, even if one of the layers is added or removed.
The only optional constraint for REST! Code-on-demand enables a client to download or extend its own capability by getting code from the server and executing it. Key point: the server can send code to clients, further extending the capabilities of the client.
I won’t go any deeper into this since it is optional. Your system is still RESTful if code-on-demand is not available.
Uniform Interface Constraint
I saved this constraint for last. Fielding shares the uniform interface as “the central feature that distinguishes the REST architectural style from other network-based styles”. It’s clear from the dissertation this constraint is one of the defining features for REST.
A uniform interface favors a generic, overarching technical contract establishing how the client and server exchange requests and responses. It can be applied uniformly to many different systems by removing any business domain language from this interface.
This constraint has four further requirements to create a uniform interface:
- Resource and Resource Identification
- Manipulation of Resources through Representations
- Self-descriptive messages
- Hypermedia as the engine of application state
A resource is the main abstraction in any REST-based system. Anything can be a resource - your driver’s license, a document, the image of your pet: all resources. Even temporal things like today’s weather or tomorrow’s lunch menu could all be resources. A resource is “a conceptual mapping to an entity or set of entities, not the entity that corresponds to the mapping at any point in time.” A resource can even map to empty concepts. For example, you might want a resource for tomorrow’s paper. This maps to tomorrow’s paper; the paper itself doesn’t exist yet, but the resource could exist.
Identifying resources is another critical aspect of defining a uniform interface. Each resource must have a unique identifier that, ideally never, ever changes. This enables clients to interact with a resource in a REST-based system reliably over time. The naming authority responsible for assigning resource identifiers should maintain this valid mapping over time. Take, for example, International Standard Book Number or ISBNs, and how they are used world-wide to assign a 13 digit unique identifier for books and other media. The International ISBN Agency is the authority responsible for maintaining and assigning this unique number.
A representation is a snapshot in time of the state of a given resource. State comes in a format described by message metadata. The format could be binary or textual key-value pairs.
Let’s say you have a resource called “ME” located with the unique resource ID of 123-12-1234. When requesting a representation of this resource, the client can form the message to indicate the ME resource’s format. For example, maybe I want a representation of ME to be in JSON. I should be able to craft a request that says, “Give the current state for the resource ME in the JSON representation.” If I wanted a different representation, I could change the requested representation to, for example, PNG and get a photo representation of the ME resource! It’s the same resource, backed by the same entity; it’s just a different representation!
All the information exchanged between the client and server should be contained in the messages between them. This means a standard set of methods, representation types, and caching controls should be in the message itself and not hidden inside of any client or server implementation.
Hypermedia as the Engine of Application State (HATEOAS)
The general idea is the client is maintaining the state of the application through the representations of resources. HATEOAS is a massive topic that I could spend way too much of your time on. The details are beyond the scope of this post. If you’d like to learn more about Hypermedia, I suggest this resource. Valid transitions are included in the representations themselves through various mechanisms (i.e., linking). The client understands everything it can do with a resource, given the current state and representation.
Going back to the ME resource, maybe one of the actions you can do is make ME exercise. The representation could include this as an available state transition.
Notice the representation has a uniform resource identifier for the state transition to exercising. The client gets this information from the current state. Assuming we send it a valid request to go from lazy to exercising using these details, we can get the representation, and see we are now exercising and the transition to exercising while exercising is missing/invalid.
And if I do this enough, my tshirtSize will eventually get small enough to no longer need exercise! Instead, I can now eat meals. All the meals.
Having a uniform interface is a crucial requirement to have a RESTful system. The messages Transferred between the client and server are REpresentations of the State for a given resource with a unique ID.
REST is an Architecture
Keen readers might’ve noticed I did not explicitly mention HTTP or Web-specific implementations. This was on purpose! REST is an architecture. It can be implemented by many different protocols as long as you can adhere to the five required constraints defined above. Sure, HTTP is a natural protocol to use as a mechanism to achieve a RESTful interaction style, but you could use something else. Want to use SOAP to implement a RESTful Web API? Sure, as long as you can make these constraints work, nothing is stopping you (I probably wouldn’t do that)!
Adhere to an Implementation’s Specification
If you are using HTTP as the technology to implement a REST-based service, follow the specification for semantics while keeping in mind the architecture’s constraints. For example, we did not talk about HTTP methods; however, you should follow the HTTP Specification around how to use each of these methods in your application. Do NOT change or misuse the communication protocol.
Representations != Resources != Entities
These concepts are completely independent of one another. Representations are the “over-the-wire” format of the resource’s state at the current time. A resource has a unique identifier for clients to access to make requests. These resources map to a thing or a collection of things, but are not the actual thing. An entity is just a “thing”. Do not think of this as a database entity or domain entity.
Taking care of designing your application not to conflate these independent concepts is key.
Representation Format Doesn’t Matter
The format of the representation doesn’t make something RESTful. I can offer a representation in HTML and still be RESTful! Consequently, a Web-based API that returns JSON does NOT mean it is RESTful.
HATEOAS is Critical
Transitioning state should be accomplished by the client sending messages to the server. The valid state transitions for a specific resource should be contained in the representation of the resource. This is at the very heart of REpresentational State Transfer!
Constraints Hold Each Other Up
Caching and Layered Systems help alleviate issues around statelessness overhead. Self-describing messages within the uniform interface enable statelessness. The client-server style of communication gives us the ability to have a layered system by evolving each independently.
If you forgo one, you end up with consequences that could severely affect your application. Plus, you won’t technically have a RESTful system.
REST isn’t Trivial
You should be pragmatic when it comes to designing a distributed system. Designing and implementing a RESTful architecture is a significant undertaking. It might not be worth the cost when a simple, remote procedure call (RPC) style of Web API can suit your requirements. Take the extremely popular Twitter API as an example; it is an HTTP-based Web API and doesn’t adhere to all the REST constraints. Does that mean it isn’t useful? Not at all. It was just the choice their engineers made when designing it.
If being RESTful is an absolute must, refer to the Richardson Maturity Model to help guide your journey.
In this article, we explored the different components of a RESTful system. We dug deep into the depths of REST theory without focusing on any implementation details. Hopefully, when in technical discussions or talking about distributed system design, you will have a better understanding of the constraints and what it takes to be RESTful. Herman Melville would be proud.
Now, go ye, and REST.
Connect with Red Hat ServicesLearn more about Red Hat Consulting
Learn more about Red Hat Training
Join the Red Hat Learning Community
Learn more about Red Hat Certification
Subscribe to the Training Newsletter
Follow Red Hat Services on Twitter
Follow Red Hat Open Innovation Labs on Twitter
Like Red Hat Services on Facebook
Watch Red Hat Training videos on YouTube
Understand the value of Red Hat Certified Professionals