What is REST?
Representational State Transfer (REST) is basically an architectural style for the web. REST specifies a set of constraints. These constraints ensure that clients (service consumers and browsers) can interact with servers in flexible ways.
Let's first understand some common terminologies:
- Server: Service provider. Exposes services which can be consumed by clients.
- Client: Service consumer. Could be a browser or another system.
- Resource: Any information can be a resource: a person, an image, a video, or a product you want to sell.
- Representation: A specific way a resource can be represented. For example, the product resource can be represented using JSON, XML, or HTML. Different clients might request different representations of the resource.
Some of the important REST constraints are listed as follows:
- Client-Server: There should be a server (service provider) and a client (service consumer). This enables loose coupling and independent evolution of the server and client as new technologies emerge.
- Stateless: Each service should be stateless. Subsequent requests should not depend on some data from a previous request being temporarily stored. Messages should be self-descriptive.
- Uniform interface: Each resource has a resource identifier. In the case of web services, we use this URI example:
/users/Jack/todos/1
. In this, URI Jack is the name of the user.1
is the ID of the todo we would want to retrieve. - Cacheable: The service response should be cacheable. Each response should indicate whether it is cacheable.
- Layered system: The consumer of the service should not assume a direct connection to the service provider. Since requests can be cached, the client might be getting the cached response from a middle layer.
- Manipulation of resources through representations: A resource can have multiple representations. It should be possible to modify the resource through a message with any of these representations.
- Hypermedia as the engine of application state (HATEOAS): The consumer of a RESTful application should know about only one fixed service URL. All subsequent resources should be discoverable from the links included in the resource representations.
An example response with the HATEOAS link is shown here. This is the response to a request to retrieve all todos:
{ "_embedded":{ "todos":[ { "user":"Jill", "desc":"Learn Hibernate", "done":false, "_links":{ "self":{ "href":"http://localhost:8080/todos/1" }, "todo":{ "href":"http://localhost:8080/todos/1" } } } ] }, "_links":{ "self":{ "href":"http://localhost:8080/todos" }, "profile":{ "href":"http://localhost:8080/profile/todos" }, "search":{ "href":"http://localhost:8080/todos/search" } } }
The preceding response includes links to the following:
- Specific todos (
http://localhost:8080/todos/1
) - Search
resource
(http://localhost:8080/todos/search
)
If the service consumer wants to do a search, it has the option of taking the search URL from the response and sending the search request to it. This would reduce coupling between the service provider and the service consumer.
The initial services we develop will not be adhering to all these constraints. As we move on to the next lessons, we will introduce you to the details of these constraints and add them to the services to make them more RESTful.