Unraveling RESTful Services
By M. Vaqqas
Introduction to RESTful Services using HTTP 1.1. Originally published in Dr. Dobbs with the title "RESTful Services a Tutorial". Re-posting here with the original title. (Feel free to copy the article in full or in parts as long as you provide the link to this article)
You may want to check out the first article in the series: https://www.dhirubhai.net/pulse/restful-architecture-mohammad-vaqqas/
More than a decade after its introduction, REST is becoming one of the most important technologies for Web applications. Its importance is likely to continue growing quickly as all technologies move towards an API orientation. Every major development language now includes frameworks for building RESTful web services. As such, it is important for web developers and architects to have a clear understanding of the REST and RESTful services. This tutorial explains REST architecturally and then dives into the details of using it for common API-based tasks.
While REST stands for Representational State Transfer, which is an architectural style for networked hypermedia applications, it is primarily used to build web services that are lightweight, maintainable, and scalable. A service based on REST is called RESTful service. REST is not dependent on any protocol but almost every RESTful service uses HTTP as its underlying protocol. In this article, I examine the creation of RESTful services with HTTP.
Features of a RESTful Service
Every system uses resources. These resources can be pictures, video files, web pages, business information, or anything that can be represented in a computer-based system. The purpose of a service is to provide a window to its clients so that they can access these resources. Service architects and developers want this service to be easy to implement, maintainable, extensible, and scalable. A RESTful design promises that and more. In general, RESTful service should have the following properties and features, which I’ll describe in more detail:
Representations
The focus of a RESTful service is on resources and how to provide access to these resources. A resource can easily be thought of as an object as in OOP. A resource can consist of other resources. While designing a system, the first thing we do is to identify the resources and determine how they are related to each other. This is similar to the first step of designing a database.? We identify entities and relations.?
Once we have identified our resources the next thing we need is to find a way to represent these resources in our system. You can use any format for representing the resources, as REST does not put a restriction on the format of a representation.?
For example, depending on your requirements, you can decide to use JSON or XML. If you are building web services that will be used by web pages for AJAX calls then JSON is a good choice. XML can be used to represent more complex resources. For example, a resource called “Person” can be represented as:
In fact, you can use more than one format and decide which one to use for a response depending on the type of client or some request parameters. Whichever format you use, a good representation should have some obvious qualities:
Messages
The client and service talk to each other via messages. Clients send a request to the server, and the server replies with a response. Apart from the actual data, these messages also contain some metadata about the message. It is important to have some background about the HTTP 1.1 request and response formats for designing RESTful web services.
HTTP Request
An HTTP Request has the following format:
<VERB> is one of the HTTP methods like GET, PUT, POST, DELETE, OPTIONS, etc
<URI> is the URI of the resource on which the operation is going to be performed
<HTTP Version> is the version of HTTP, generally “HTTP v1.1”
<Request Header> contains the metadata as a collection of key-value pairs of headers and their values. These settings contain information about the message and its sender like client type, the formats the client supports, the format type of the message body, cache settings for the response, and a lot more information.?
<Request Body> is the actual message content. In a RESTful service that’s where the representations of resources sit in a message.
There are no tags or markups to mark the beginning or end of a section in an HTML message.?
Here is a sample POST request message, which is supposed to insert a new resource ‘Person’?
Listing 3: A Sample POST Request
We can see the POST command which is followed by the URI and the HTTP version. This request also contains some request headers. The Host header is the address of the server. Content-Type tells about the type of content in the message body. Content-Length is the length of the data in the message body. Content length can be used to verify that the entire message body has been received. Notice there are no start or end tags in this message.
Here is an actual GET request that was created by my browser when I tried to visit the HTTP 1.1 specifications on w3.org:
There is no message body in this request. The Accept header tells the server about the various presentation formats this client supports. A server, if it supports more than one representation format, can decide the representation format for a response on runtime depending on the value of the Accept header. User-Agent contains information about the type of client who made this request. Accept-Encoding/Language tells about the encoding and language this client supports.?
HTTP Response
Format of an HTTP Response
The server returns <response code>, which contains the status of the request. This response code is generally the 3-digit HTTP status code. [? https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ]?
<Response Header> contains the metadata and settings about the response message.
<Response Body> contains the representation if the request was successful.
Here is the actual response I received for the request cited above in Listing 3:
The response code “200 OK” means that everything went well and the response message body contains a valid representation of the resource I requested. In this case, the representation is an HTML document that is declared by the Content-Type header in the response header. The headers in the message are quite self-explanatory. We will discuss some of these headers later in this article. There are so many other such attributes. If you wish to explore them all you can visit “https://www.w3.org/Protocols/rfc2616/rfc2616.html HTTP/1.1”.
You can catch and inspect such HTTP requests and responses using a free tool called Fiddler? [ https://www.telerik.com/download/fiddler” ]
Addressing Resources
REST requires each resource to have at least one URI. A RESTful service uses a directory hierarchy like human readable URIs to address its resources. The job of a URI is to identify a resource or a collection of resources. The actual operation is determined by an HTTP verb. The URI should not say anything about the operation or action. This enables us to call the same URI with different HTTP verbs to perform different operations.?
Suppose we have a database of persons and we wish to expose it to the outer world through a service. A resource ‘person’ can be addressed like this
The above URL has the following format: Protocol://ServiceName/ResourceType/ResourceID
Some important recommendations for well-structured URIs:
Query Parameters in URI
The preceding URI is constructed with the help of a query parameter:
The query parameter approach will work just fine. REST does not stop you from using query parameters. However, this approach has a few disadvantages.?
The basic purpose of query parameters is to provide parameters to an operation that needs the data items. For example, if you wish the format of the presentation to be decided by the client. You can achieve that through a parameter like this:
https://MyService/Persons/1?format=xml&encoding=UTF8 or https://MyService/Persons/1?format=json&encoding=UTF8 Including the parameters ‘format’ and ‘encoding’ here in the main URI in a parent-child hierarchy will not be logically correct as they have no such relation:
领英推荐
Query parameters also allow optional parameters. This is not possible otherwise in a URI. Use query parameters only for the use they are intended for providing parameter values to a process.?
Uniform Interface
A RESTful system should have a uniform interface. HTTP 1.1 provides a set of methods, called verbs. Among these, the most important are:
A Safe operation is an operation that does not have any effect on the original value of the resource. For example, the mathematical operation divide by 1 is a safe operation as no matter how many times you divide a number by 1 the original value will not change. An Idempotent operation is an operation that gives the same result no matter how many times you perform it. For example mathematical operation multiplied by zero is idempotent as no matter how many times you multiply a number by zero the result is always the same. Similarly, a Safe HTTP method does not make any changes to the resource on the server. An Idempotent HTTP method has the same effect no matter how many times it is performed. Classifying methods as Safe and Idempotent makes it easy to predict the results in the unreliable environment of the web where the client may fire the same request again.
GET is probably the most popular method on the web. It is used to fetch a resource. HEAD returns only the response headers with an empty body. This method can be used in a scenario when you do not need the entire representation of the resource. For example, HEAD can be used to quickly check whether a resource exists on the server or not.
The method OPTIONS is used to get a list of allowed operations on the resource. For example consider the request:
OPTIONS https://MyService/Persons/1 HTTP/1.1
HOST: MyService
The service after authorizing and authenticating the request can return something like
200 OK Allow: HEAD, GET, PUT
The second line contains the list of operations that are allowed for this client.
You should use these methods only for the purpose they are intended for. For instance, never use GET to create or delete a resource on the server. If you do so this will confuse your clients and they might end up doing operations they did not intend to.
To illustrate this let’s consider this request:?
GET https://MyService/DeletePersons/1 HTTP/1.1
HOST: MyService
By HTTP 1.1 specification a GET request is supposed to fetch resources from the server. But this is so easy to implement your service such that this request actually deletes a Person. This request will work perfectly but this is not a RESTful design. Instead, use the DELETE method to delete a resource like this:
DELETE https://MyService/Persons/1 HTTP/1.1
HOST: MyService
REST recommends a uniform interface and HTTP provides you with that uniform interface. However, it is up to the service architects and developers to keep it uniform.
Difference between PUT and POST
The short descriptions of these two methods I provided above are almost the same. These two methods confuse a lot of developers. So let’s discuss these separately.?
The key difference between PUT and POST is that PUT is idempotent while POST is not. No matter how many times you send a PUT request the results will be the same.? While POST is not an idempotent method. Making a POST multiple times may result in multiple resources getting created on the server.
Another difference is that with PUT you must always specify the complete URI of the resource. This implies that the client should be able to construct the URI of a resource even if it does not yet exist on the server. This is possible when it is the client’s job to choose a unique name or id for the resource. Creating a user on the server requires the client to choose a user ID. If the client is not able to guess the complete URI of the resource then you have no option but to use POST.
It is clear from the above table that a PUT request will not modify or create more than one resource no matter how many times it is fired (if the URI is the same). There is no difference between PUT and POST if the resource already exists, both update the existing resource. The third request (POST https://MyService/Persons/) will create a resource each time it is fired. A lot of developers think that REST does not allow POST to be used for update operations; however, REST imposes no such restrictions.
Stateless
A RESTful service is stateless and does not maintain the application state for any client. A request cannot be dependent on a past request and service treats each request independently. HTTP is a stateless protocol by design and you need to do something extra to implement a state-full service using HTTP. But this is really easy to implement state-full services with current technologies. We need a clear understanding of a stateless and state-full design so that we can avoid a state-full design.
A Stateless design:
Request1: GET https://MyService/Persons/1 HTTP/1.1 Request2: GET https://MyService/Persons/2 HTTP/1.1
Each of these requests can be treated separately.
A stateful design:
Request1: GET https://MyService/Persons/1 HTTP/1.1 Request2: GET https://MyService/NextPerson? HTTP/1.1
To process the second request, the server needs to remember the last PersonID client fetched. In other words, the server needs to remember the current state—otherwise Request2 cannot be processed. Design your service in a way that a request never refers to a previous request. Stateless services are easier to host, easy to maintain, and more scalable. Plus, such services can provide better response time to requests, as it is much easier to load and balance them.
Links between Resources
A resource representation can contain links to other resources like an HTML page contains links to other pages. The representations returned by the service should drive the process flow as in the case of a website. When you visit any website you are presented with an index page. You click one of the links and move to another page and so on. Here the representation is the HTML documents and the user is driven through the website by these HTML documents themselves. The user does not need a map before coming to a website. A service can be (and should be) designed in the same manner.?
Let’s consider the case in which a client requests one resource that contains multiple other resources. Instead of dumping all these resources, you can list all the resources and provide links to these resources. Links help keep the representations small in size.
For example, if multiple persons can be part of a Club, then a Club can be represented in MyService as:
Caching
Caching is the concept of storing the generated results and using the stored results instead of generating them repeatedly if the same request arrives in near future. This can be done on the client, the server, or any other component between them, such as a proxy server. Caching is a great way of enhancing service performance, but if not managed properly can result in clients being served stale results.
Caching can be controlled using these HTTP headers:
Duration passed in seconds since this was fetched from the server. Can be inserted by an intermediary component.?
Values of these headers can be used in combination with the directives in the Cache-Control header to check if the cached results are still valid or not. The most common directives for Cache-Control header:
You can see some of these headers and directives above in Listing 5. Depending on the nature of the resources, a service can decide the values of these headers and directives. For example, a service providing stock market updates would keep the cache age limit to as low as possible or even turn off caching completely as this is a piece of critical information and users should get the latest results all the time. While a public pictures repository whose contents do not change so frequently would use longer caching age and slack caching rules. The server, the client, and any intermediate component between them should follow these directives sincerely else it will result in outdated information getting served.
Documenting RESTful APIs
RESTful services do not necessarily require a document to help clients discover them. Due to URIs, links, and a uniform interface, it is extremely simple to discover RESTful services at runtime. A client can simply know the base address of the service and from there, it can discover the service on its own by traversing through the resources using links. The method OPTION can be used effectively in the process of discovering a service.?
This does not mean that RESTful services require no documentation at all. There is no excuse for not documenting your service. You should document every resource and URI for the client developers. You can use any format for structuring your document but it should contain enough information about resources, URIs, Available Methods, and any other information required for accessing your service. Table X is a sample documentation of MyService. This is a simple and short document that contains all the aspects of MyService and should be sufficient for developing a client.
Service Name: MyService Address: https://MyService/
You may also like to document the representations of each resource and provide some sample representations.?
Conclusion
REST is a great way of developing lightweight web services that are easy to implement, maintain and discover. HTTP provides an excellent interface to implement RESTful services with features like a uniform interface and caching. However, it is up to developers to implement and utilize these features correctly. If we get the basics right a RESTful service can be easily implemented using any of the existing technologies like Python, .NET, or Java. I hope this article provides enough information for you to start developing your own RESTful services.
References