© Balaji Varanasi and Maxim Bartkov 2022
B. Varanasi, M. BartkovSpring RESThttps://doi.org/10.1007/978-1-4842-7477-4_1

1. Introduction to REST

Balaji Varanasi1   and Maxim Bartkov2
(1)
Salt Lake City, UT, USA
(2)
Kharkov, Ukraine
 
In this chapter, we will learn the following:
  • REST fundamentals

  • REST resources and their representations

  • HTTP methods and status codes

  • Richardson’s Maturity Model

Today, the Web has become an integral part of our lives—from checking statuses on Facebook to ordering products online to communicating via email. The success and ubiquity of the Web have resulted in organizations applying the Web’s architectural principles to building distributed applications. In this chapter, we will take a deep dive into REST, an architectural style that formalizes these principles.

What Is REST?

REST stands for REpresentational State Transfer and is an architectural style for designing distributed network applications. Roy Fielding coined the term REST in his PhD dissertation1 and proposed the following six constraints or principles as its basis:
  • Client-server—Concerns should be separated between clients and servers. This enables client and server components to evolve independently and in turn allows the system to scale.

  • Stateless—The communication between client and server should be stateless. The server need not remember the state of the client. Instead, clients must include all of the necessary information in the request so that the server can understand and process it.

  • Layered system—Multiple hierarchical layers such as gateways, firewalls, and proxies can exist between client and server. Layers can be added, modified, reordered, or removed transparently to improve scalability.

  • Cache—Responses from the server must be declared as cacheable or noncacheable. This would allow the client or its intermediary components to cache responses and reuse them for later requests. This reduces the load on the server and helps improve the performance.

  • Uniform Interface—All interactions between client, server, and intermediary components are based on the uniformity of their interfaces. This simplifies the overall architecture as components can evolve independently as long as they implement the agreed-on contract. The Uniform Interface constraint is further broken down into four subconstraints: resource identification, resource representations, self-descriptive messages, and Hypermedia as the Engine of Application State, or HATEOAS. We will examine some of these guiding principles in the later sections of this chapter.

  • Code on demand—Clients can extend their functionality by downloading and executing code on demand. Examples include JavaScript scripts, Java applets, Silverlight, and so on. This is an optional constraint.

Applications that adhere to these constraints are considered to be RESTful. As you might have noticed, these constraints don’t dictate the actual technology to be used for developing applications. Instead, adherence to these guidelines and best practices would make an application scalable, visible, portable, reliable, and able to perform better. In theory, it is possible for a RESTful application to be built using any networking infrastructure or transport protocol. In practice, RESTful applications leverage features and capabilities of the Web and use HTTP as the transport protocol.

The Uniform Interface constraint is a key feature that distinguishes REST applications from other network-based applications. Uniform Interface in a REST application is achieved through abstractions such as resources, representations, URIs, and HTTP methods. In the next sections, we will look at these important REST abstractions.

Understanding Resources

The key abstraction of information in REST is a resource.

—Roy Fielding

Fundamental to REST is the concept of resource. A resource is anything that can be accessed or manipulated. Examples of resources include “videos,” “blog entries,” “user profiles,” “images,” and even tangible things such as persons or devices. Resources are typically related to other resources. For example, in an ecommerce application, a customer can place an order for any number of products. In this scenario, the product resources are related to the corresponding order resource. It is also possible for a resource to be grouped into collections. Using the same ecommerce example, “orders” is a collection of individual “order” resources.

Identifying Resources

Before we can interact and use a resource, we must be able to identify it. The Web provides the Uniform Resource Identifier, or URI, for uniquely identifying resources. The syntax of a URI is
scheme:scheme-specific-part

The scheme and the scheme-specific-part are separated using a semicolon. Examples of a scheme include http or ftp or mailto and are used to define the semantics and interpretation of the rest of the URI. Take the example of the URI—http://www.apress.com/9781484208427. The http portion of the example is the scheme; it indicates that an HTTP scheme should be used for interpreting the rest of the URI. The HTTP scheme, defined as part of RFC 7230,2 indicates that the resource identified by our example URI is located on a machine with host name apress.com.

Table 1-1 shows examples of URIs and the different resources they represent.
Table 1-1

URI and Resource Description

URI

Resource description

http://blog.example.com/posts

Represents a collection of blog post resources.

http://blog.example.com/posts/1

Represents a blog post resource with identifier “1”; such resources are called singleton resources.

http://blog.example.com/posts/1/comments

Represents a collection of comments associated with the blog entry identified by “1”; collections such as these that reside under a resource are referred to as subcollections.

http://blog.example.com/posts/1/comments/245

Represents the comment resource identified by “245.”

Even though a URI uniquely identifies a resource, it is possible for a resource to have more than one URI. For example, Facebook can be accessed using URIs https://www.facebook.com and https://www.fb.com. The term URI aliases is used to refer to such URIs that identify the same resources. URI aliases provide flexibility and added convenience such as having to type fewer characters to get to the resource.

URI Templates

When working with REST and a REST API, there will be times where you need to represent the structure of a URI rather than the URI itself. For example, in a blog application, the URI http://blog.example.com/2014/posts would retrieve all the blog posts created in the year 2014. Similarly, the URIs http://blog.example.com/2013/posts, http://blog.example.com/2012/posts, and so forth would return blog posts corresponding to the years 2013, 2012, and so on. In this scenario, it would be convenient for a consuming client to know the URI structure http://blog.example.com/year/posts that describes the range of URIs rather than individual URIs.

URI templates, defined in RFC 6570 (http://tools.ietf.org/html/rfc6570), provide a standardized mechanism for describing URI structure. The standardized URI template for this scenario could be

http://blog.example.com/{year}/posts

The curly braces {} indicate that the year portion of the template is a variable, often referred to as a path variable. Consuming clients can take this URI template as input, substitute the year variable with the right value, and retrieve the corresponding year’s blog posts. On the server side, URL templates allow the server code to parse and retrieve the values of the variables or selected portions of URI easily.

Representation

RESTful resources are abstract entities. The data and metadata that make a RESTful resource need to be serialized into a representation before it gets sent to a client. This representation can be viewed as a snapshot of a resource’s state at a given point in time. Consider a database table in an ecommerce application that stores information about all the available products. When an online shopper uses their browser to buy a product and requests its details, the application would provide the product details as a web page in HTML. Now, when a developer writing a native mobile application requests product details, the ecommerce application might return those details in XML or JSON format. In both scenarios, the clients didn’t interact with the actual resource—the database record-holding product details. Instead, they dealt with its representation.

Note

REST components interact with a resource by transferring its representations back and forth. They never directly interact with the resource.

As noted in this product example, the same resource can have several representations. These representations can range from text-based HTML, XML, and JSON formats to binary formats such as PDFs, JPEGs, and MP4s. It is possible for the client to request a particular representation, and this process is termed as content negotiation . Here are the two possible content negotiation strategies:
  • Postfixing the URI with the desired representation—In this strategy, a client requesting product details in JSON format would use the URI http://www.example.com/products/143.json. A different client might use the URI http://www.example.com/products/143.xml to get product details in XML format.

  • Using the Accept header—Clients can populate the HTTP Accept header with the desired representation and send it along with the request. The application handling the resource would use the Accept header value to serialize the requested representation. The RFC 26163 provides a detailed set of rules for specifying one or more formats and their priorities.

Note

JSON has become the de facto standard for REST services. All of the examples in this book use JSON as the data format for requests and responses.

HTTP Methods

The “Uniform Interface” constraint restricts the interactions between client and server through a handful of standardized operations or verbs. On the Web, the HTTP standard4 provides eight HTTP methods that allow clients to interact and manipulate resources. Some of the commonly used methods are GET, POST, PUT, and DELETE. Before we delve deep into HTTP methods, let’s review their two important characteristics—safety and idempotency.

Note

The HTTP specification uses the term method to denote HTTP actions such as GET, PUT, and POST. However, the term HTTP verb is also used interchangeably.

Safety

A HTTP method is said to be safe if it doesn’t cause any changes to the server state. Consider methods such as GET or HEAD, which are used to retrieve information/resources from the server. These requests are typically implemented as read-only operations without causing any changes to the server’s state and, hence, considered safe.

Safe methods are used to retrieve resources. However, safety doesn’t mean that the method must return the same value every time. For example, a GET request to retrieve Google stock might result in a different value for each call. But as long as it didn’t alter any state, it is still considered safe.

In real-world implementations, there may still be side effects with a safe operation. Consider the implementation in which each request for stock prices gets logged in a database. From a purist perspective, we are changing the state of the entire system. However, from a practical standpoint, because these side effects were the sole responsibility of the server implementation, the operation is still considered to be safe.

Idempotency

An operation is considered to be idempotent if it produces the same server state whether we apply it once or any number of times. HTTP methods such as GET, HEAD (which are also safe), PUT, and DELETE are considered to be idempotent, guaranteeing that clients can repeat a request and expect the same effect as making the request once. The second and subsequent requests leave the resource state in exactly the same state as the first request did.

Consider the scenario in which you are deleting an order in an ecommerce application. On successful completion of the request, the order no longer exists on the server. Hence, any future requests to delete that order would still result in the same server state. By contrast, consider the scenario in which you are creating an order using a POST request. On successful completion of the request, a new order gets created. If you were to re-“POST” the same request, the server simply honors the request and creates a new order. Because a repeated POST request can result in unforeseen side effects, POST is not considered to be idempotent.

GET

The GET method is used to retrieve a resource’s representation. For example, a GET on the URI http://blog.example.com/posts/1 returns the representation of the blog post identified by 1. By contrast, a GET on the URI http://blog.example.com/posts retrieves a collection of blog posts. Because GET requests don’t modify server state, they are considered to be safe and idempotent.

A hypothetical GET request to http://blog.example.com/posts/1 and the corresponding response are shown here.
GET      /posts/1 HTTP/1.1
Accept:  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Host: blog.example.com
Content-Type: text/html; charset=UTF-8
Date: Sat, 10 Jan 2015 20:16:58 GMT
Server: Apache
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns:="http://www.w3.org/1999/xhtml">
      <head>
         <title>First Post</title>
      </head>
      <body>
           <h3>Hello World!!</h3>
      </body>
</html>

In addition to the representation, the response to GET requests includes metadata associated with the resource. This metadata is represented as a sequence of key value pairs called HTTP headers. Content-Type and Server are examples of the headers that you see in this response. Because the GET method is safe, responses to GET requests can be cached.

The simplicity of the GET method is often abused, and it is used to perform operations such as deleting or updating a resource’s representation. Such usage violates standard HTTP semantics and is highly discouraged.

HEAD

On occasions, a client would like to check if a particular resource exists and doesn’t really care about the actual representation. In another scenario, the client would like to know if a newer version of the resource is available before it downloads it. In both cases, a GET request could be “heavyweight” in terms of bandwidth and resources. Instead, a HEAD method is more appropriate.

The HEAD method allows a client to only retrieve the metadata associated with a resource. No resource representation gets sent to the client. This metadata represented as HTTP headers will be identical to the information sent in response to a GET request. The client uses this metadata to determine resource accessibility and recent modifications. Here is a hypothetical HEAD request and the response.
HEAD     /posts/1 HTTP/1.1
Accept:  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Host: blog.example.com
Connection:  Keep-Alive
Content-Type: text/html; charset=UTF-8
Date: Sat, 10 Jan 2015 20:16:58 GMT
Server: Apache

Like GET, the HEAD method is also safe and idempotent and responses can be cached on the client.

DELETE

The DELETE method, as the name suggests, requests a resource to be deleted. On receiving the request, a server deletes the resource. For resources that might take a long time to delete, the server typically sends a confirmation that it has received the request and will work on it. Depending on the service implementation, the resource may or may not be physically deleted.

On successful deletion, future GET requests on that resource would yield a “Resource Not Found” error via HTTP status code 404. We will be covering status codes in just a minute.

In this example, the client requests a post identified by 1 to be deleted. On completion, the server could return a status code 200 (OK) or 204 (No Content), indicating that the request was successfully processed.
Delete /posts/1  HTTP/1.1
Content-Length: 0
Content-Type: application/json
Host: blog.example.com
Similarly, in this example, all comments associated with post #2 get deleted.
Delete /posts/2/comments HTTP/1.1
Content-Length: 0
Content-Type: application/json
Host: blog.example.com

Because DELETE method modifies the state of the system, it is not considered to be safe. However, the DELETE method is considered idempotent; subsequent DELETE requests would still leave the resource and the system in the same state.

PUT

The PUT method allows a client to modify a resource state. A client modifies the state of a resource and sends the updated representation to the server using a PUT method. On receiving the request, the server replaces the resource’s state with the new state.

In this example, we are sending a PUT request to update a post identified by 1. The request contains an updated blog post’s body along with all of the other fields that make up the blog post. The server, on successful processing, would return a status code 200, indicating that the request was processed successfully.
PUT /posts/1     HTTP/1.1
Accept: */*
Content-Type: application/json
Content-Length: 65
Host: blog.example.com
BODY
{"title": "First Post","body": "Updated Hello World!!"}

Consider the case in which we just wanted to update the blog post title. The HTTP semantics dictate that as part of the PUT request, we send the full resource representation, which includes the updated title as well as other attributes such as blog post body and so on that didn’t change. However, this approach would require that the client has the complete resource representation, which might not be possible if the resource is very big or has a lot of relationships. Additionally, this would require higher bandwidth for data transfers. So, for practical reasons, it is acceptable to design your API that tends to accept partial representations as part of a PUT request.

Note

To support partial updates, a new method called PATCH has been added as part of RFC 5789 (http://www.ietf.org/rfc/rfc5789.txt). We will be looking at the PATCH method later in this chapter.

Clients can also use PUT method to create a new resource. However, it will only be possible when the client knows the URI of the new resource. In a blogging application, for example, a client can upload an image associated with a blog post. In that scenario, the client decides the URL for the image as shown in this example:
PUT http://blog.example.com/posts/1/images/author.jpg

PUT is not a safe operation, as it changes the system state. However, it is considered idempotent, as putting the same resource once or more than once would produce the same result.

POST

The POST method is used to create resources. Typically, it is used to create resources under subcollections—resource collections that exist under a parent resource. For example, the POST method can be used to create a new blog entry in a blogging application. Here, “posts” is a subcollection of blog post resources that reside under a blog parent resource.
POST /posts      HTTP/1.1
Accept: */*
Content-Type: application/json
Content-Length: 63
Host: blog.example.com
BODY
{"title": "Second Post","body": "Another Blog Post."}
Content-Type: application/json
Location: posts/12345
Server: Apache

Unlike PUT, a POST request doesn’t need to know the URI of the resource. The server is responsible for assigning an ID to the resource and deciding the URI where the resource is going to reside. In the previous example, the blogging application will process the POST request and create a new resource under http://blog.example.com/posts/12345, where “12345” is the server generated id. The Location header in the response contains the URL of the newly created resource.

The POST method is very flexible and is often used when no other HTTP method seems appropriate. Consider the scenario in which you would like to generate a thumbnail for a JPEG or PNG image. Here we ask the server to perform an action on the image binary data that we are submitting. HTTP methods such as GET and PUT don’t really fit here, as we are dealing with an RPC-style operation. Such scenarios are handled using the POST method.

Note

The term “controller resource” has been used to describe executable resources that take inputs, perform some action, and return outputs. Although these types of resources don’t fit the true REST resource definition, they are very convenient to expose complex operations.

The POST method is not considered safe, as it changes system state. Also, multiple POST invocations would result in multiple resources being generated, making it nonidempotent.

PATCH

As we discussed earlier, the HTTP specification requires the client to send the entire resource representation as part of a PUT request. The PATCH method proposed as part of RFC 5789 (http://tools.ietf.org/html/rfc5789) is used to perform partial resource updates. It is neither safe nor idempotent. Here is an example that uses PATCH method to update a blog post title.
PATCH /posts/1   HTTP/1.1
Accept: */*
Content-Type: application/json
Content-Length: 59
Host: blog.example.com
BODY
{"replace": "title","value": "New Awesome title"}

The request body contains a description of changes that need to be performed on the resource. In the example, the request body uses the "replace" command to indicate that the value of the "title" field needs to be replaced.

There is no standardized format for describing the changes to the server as part of a PATCH request. A different implementation might use the following format to describe the same change:
{"change" : "name", "from" : "Post Title", "to" : "New Awesome Title"}
Currently, there is a work in progress (http://tools.ietf.org/html/draft-ietf-appsawg-json-patch) for defining a PATCH format for JSON. This lack of standard has resulted in implementations that describe change sets in a simpler format, as shown here:
{"name" : "New Awesome Title"}
Crud and HTTP Verbs
Data-driven applications typically use the term CRUD to indicate four basic persistence functions—Create, Read, Update, and Delete. Some developers building REST applications have mistakenly associated the four popular HTTP verbs GET, POST, PUT, and DELETE with CRUD semantics. The typical association often seen is
Create -> POST
Update -> PUT
Read -> GET
Delete -> DELETE

These correlations are true for Read and Delete operations. However, it is not as straightforward for Create/Update and POST/PUT. As you have seen earlier in this chapter, PUT can be used to create a resource as long as idempotency constraint is met. In the same way, it was never considered non-RESTful if POST is used for update (http://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post). It is also possible for a client to use PATCH for updating a resource.

Therefore, it is important for API designers to use the right verbs for a given operation than simply using a 1-1 mapping with CRUD.

HTTP Status Codes

The HTTP status codes allow a server to communicate the results of processing a client’s request. These status codes are grouped into the following categories:
  • Informational codes—Status codes indicating that the server has received the request but hasn’t completed processing it. These intermediate response codes are in the 100 series.

  • Success codes—Status codes indicating that the request has been successfully received and processed. These codes are in the 200 series.

  • Redirection codes—Status codes indicating that the request has been processed but the client must perform an additional action to complete the request. These actions typically involve redirecting to a different location to get the resource. These codes are in the 300 series.

  • Client error codes—Status codes indicating that there was an error or a problem with client’s request. These codes are in the 400 series.

  • Server error codes—Status codes indicating that there was an error on the server while processing the client’s request. These codes are in the 500 series.

The HTTP status codes play an important role in REST API design as meaningful codes help communicate the right status, enabling the client to react appropriately. Table 1-2 shows some of the important status codes into which you typically run.
Table 1-2

HTTP status codes and their descriptions

Status code

Description

100 (Continue)

Indicates that the server has received the first part of the request and the rest of the request should be sent.

200 (OK)

Indicates that all went well with the request.

201 (Created)

Indicates that request was completed and a new resource got created.

202 (Accepted)

Indicates that request has been accepted but is still being processed.

204 (No Content)

Indicates that the server has completed the request and has no entity body to send to the client.

301 (Moved Permanently)

Indicates that the requested resource has been moved to a new location and a new URI needs to be used to access the resource.

400 (Bad Request)

Indicates that the request is malformed and the server is not able to understand the request.

401 (Unauthorized)

Indicates that the client needs to authenticate before accessing the resource. If the request already contains client’s credentials, then a 401 indicates invalid credentials (e.g., bad password).

403 (Forbidden)

Indicates that the server understood the request but is refusing to fulfill it. This could be because the resource is being accessed from a blacklisted IP address or outside the approved time window.

404 (Not Found)

Indicates that the resource at the requested URI doesn’t exist.

406 (Not Acceptable)

Indicates that the server is capable of processing the request; however, the generated response may not be acceptable to the client. This happens when the client becomes too picky with its accept headers.

500 (Internal Server Error)

Indicates that there was an error on the server while processing the request and that the request can’t be completed.

503 (Service Unavailable)

Indicates that the request can’t be completed, as the server is overloaded or going through scheduled maintenance.

Richardson’s Maturity Model

The Richardson’s Maturity Model (RMM), developed by Leonard Richardson, classifies REST-based web services on how well they adhere to REST principles. Figure 1-1 shows the four levels of this classification.
../images/332520_2_En_1_Chapter/332520_2_En_1_Fig1_HTML.png
Figure 1-1

RMM levels

RMM can be valuable in understanding the different styles of web service and their designs, benefits, and trade-offs.

Level Zero

This is the most rudimentary maturity level for a service. Services in this level use HTTP as the transport mechanism and perform remote procedure calls on a single URI. Typically, POST or GET HTTP methods are employed for service calls. SOAP- and XML-RPC-based web services fall under this level.

Level One

The next level adheres to the REST principles more closely and introduces multiple URIs, one per resource. Complex functionality of a large service endpoint is broken down into multiple resources. However, services in this layer use one HTTP verb, typically POST, to perform all of the operations.

Level Two

Services in this level leverage HTTP protocol and make the right use of HTTP verbs and status codes available in the protocol. Web services implementing CRUD operations are good examples of level two services.

Level Three

This is the most mature level for a service and is built around the notion of Hypermedia as the Engine of Application State, or HATEOAS. Services in this level allow discoverability by providing responses that contain links to other related resources and controls that tell the client what to do next.

Building a RESTful API

Designing and implementing a beautiful RESTful API is no less than an art. It takes time, effort, and several iterations. A well-designed RESTful API allows your end users to consume the API easily and makes its adoption easier. At a high level, here are the steps involved in building a RESTful API:
  1. 1.

    Identify resources—Central to REST are resources. We start modeling different resources that are of interest to our consumers. Often, these resources can be the application’s domain or entities. However, a one-to-one mapping is not always required.

     
  2. 2.

    Identify endpoints—The next step is to design URIs that map resources to endpoints. In Chapter 4, we will look at best practices for designing and naming endpoints.

     
  3. 3.

    Identify actions—Identify the HTTP methods that can be used to perform operations on the resources.

     
  4. 4.

    Identify responses—Identify the supported resource representation for the request and response along with the right status codes to be returned.

     

In the rest of the book, we will look at best practices for designing a RESTful API and implementing it using Spring technologies.

Summary

REST has become the de facto standard for building services today. In this chapter, we covered the fundamentals of REST and abstractions such as resources, representations, URIs, and HTTP methods that make up REST’s Uniform Interface. We also looked at RMM, which provides a classification of REST services.

In the next chapter, we will take a deep dive into Spring and its related technologies that simplify REST service development.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.173.53