Hello! It's been a bit confusing for me in the past to differentiate between a Web Service and a RESTful Web Service and hence I thought of sharing this with you all.
This article explains what a RESTful Service actually is and how the ASP.NET Web API helps with the creation of such services.
What Is a Restful Service?
Representational State Transfer (REST) is an architectural style. A service that conforms to the REST constraints is referred to as being RESTful.
To be RESTful, a service has to conform to the following mandatory constraints:
- Client-Server constraint, which is based on the separation of concerns, is about separating user interface concerns from data storage concerns. Clients are not concerned with data storage, which is a concern of servers, and servers are not concerned with the user interface or user state, which are concerns of clients.
- Stateless constraint, is about each request being an independent self-contained unit with all the necessary information for the server to service the request without looking at anything else for the context.
- Cache constraint, is about the server being able to label a response as Cacheable or not, so that the client handles the response appropriately from the point of view of later use.
- Layered constraint, is about composing the system into layers, with each layer being able to see and interact with only its immediate neighbor. A layer cannot see through its neighbor. Between the client and the server, there could be any number of intermediaries; caches, tunnels, proxies, and so on.
- Uniform Interface constraint, is about providing a uniform interface for identification of resources, the manipulation of resources through representations, self-descriptive messages, and hypermedia as the engine of the application state.
Let's see how a service built with the ASP.NET Web API Framework satisfies the given constraints.
The client-server constraint is an easy one to satisfy since the ASP.NET Web API is all about responding to the client request with the data, without bothering about the client state or how data will be presented to the end user.
The stateless constraint can also be easily satisfied, unless something horrible is done such as using the ASP.NET session state from the web API.
ASP.NET MVC supports the OutputCache attribute that can be used to control output caching. The ASP.NET Web API has no built in ways to support this feature out of the box, but it's easy to roll out our own action filter attribute. The ASP.NET Web API can use a Cache-Control response header to label a response as Cacheable or not. By default, Cache-Control is set to no-cache and the response is not cached. This way it satisfies the Cache constraint.
The layered constraint is more along the infrastructure line-proxies, firewalls, and so on. There is nothing special that needs to be done from the ASP.NET Web API to satisfy this constraint.
The uniform interface constraint includes the following four constraints and is a key factor in deciding if an HTTP service is RESTful or not:
- Identification of resources
- Manipulation of resources through representations
- Self-descriptive messages
- Hypermedia as the engine of application state (HATEOAS)
Let's have a look at a unique interface constraint in detail through each of the four constraints.
1. Identification of Resources
A resource is any data that a web API sends to its clients. Examples could be an individual employee in your company, a product that your company sells etc. In the real world, a product or an employee could be uniquely identified through an identifier, such as a product ID or an employee ID.
In the case of RESTful web services, a resource is identified by a Uniform Resource Identifier (URI). An employee with an identifier of 12345 will be represented by http://myServer/employees/12345. In the case of the ASP.NET Web API, the URI can be slightly different and it includes "api" by default in the URI, so it will be more like http://myServer/api/employees/12345. If you fire up an instance of Internet Explorer, enter that URI in the address bar, and press Enter then Internet Explorer does an HTTP GET and you will get the JSON representation of the resource, which is an employee with the ID of 12345 in this case.
From the .NET code point of view (see Listing 2-1), the corresponding class will be EmployeesController, which is a subclass of ApiController and the method that executes to create the resource representation to be sent back to the client in its Get(int) method. Observe the code snippet below:
Picture 1 - Identification of Resources
You see here that a known resource with the URI representation http://myServer/api/employee/12345 is accessed using the GET HTTP Method. A list of employees is also a resource identified by http://myServer/api/employees pointing to the GetAllEmployees() method.
2. Manipulation of Resources through Representations
The example of a user typing http://myServer/api/employees/12345 in Internet Explorer can be described as a user requesting a resource using the GET verb and getting back the employee JSON, which is the representation of the resource. GET is guaranteed not to cause any side effect and is said to be nullipotent; nothing happens to the system's state, even when called multiple times or not called at all. In other words, the system state will be the same for all the following scenarios: (1) method was not called at all, (2) method was called once, and (3) method was called multiple times.
Other important verbs are POST, PUT, and DELETE. POST is for creating a new resource, PUT is for updating an existing resource, and DELETE is for deleting an existing resource. PUT and DELETE are idempotent; the effect to the system state will be the same as that of the first call, even when called multiple times subsequent to the first call.
To create a new employee, the client sends a POST request, with the new employee (JSON or XML representation) in the body of the request. This request gets mapped to a method with a name starting with Post, which is Post(Employee) in this case.
Updating an employee is the same as creating a new employee except that the PUT verb is used and mapping is based on the name starting with Put. One important difference compared to POST is that PUT is idempotent. If a user sends multiple requests to update an employee to the same state, no error must be sent back.
Deleting an employee is similar except that a resource representation is not needed. A DELETE request against the URI will be sufficient to delete the resource. Similar to PUT, the DELETE method is also idempotent. Even if the underlying data source sends an error back when the employee to be deleted no longer exists, because it is already deleted in response to the previous request then no error must be sent back.
Picture 2 - Manipulation of Resources through representations
For all the preceding actions, a status code is the means through which the status of the action is communicated back. By default it is 200 – OK, indicating success. As a special case, 201 – Created gets sent for POST, when a resource was created. 401 – Not Authorized gets sent when a user requests an action on a resource that requires the user to be authenticated and that user has either not provided the credentials or provided invalid credentials. 404 – Not Found gets sent when the user has requested an action on a resource that does not exist.
3. Self-Descriptive Messages
A resource can have multiple representations, JSON and XML being just two examples. A request body having a specific representation of a resource must have a self-description of the representation so that it is parsed and handled correctly. The same holds for responses.
In the ASP.NET Web API, the Multipurpose Internet Mail Extensions (MIME) type determines how the web API serializes or deserializes the message body. There is built-in support for XML, JSON, and form-url encoded data.
Let's take the case of a request to create a new employee, the corresponding code snippet in the picture below, to review a few scenarios.
Picture 3- Self-Descriptive Messages
Scenario 1: JSON Representation
Here is an example of a request–response message pair with JSON being the content type for both messages. The web API determines the media-type formatter to be used based on the content type. Because it is JSON, it uses JsonMediaTypeFormatter to deserialize JSON in the CLR object of type Employee named value. Again on the way out, the CLR object to be returned, in this case an object of Employee type, is serialized into JSON. If the request content type comes in as XML then XmlMediaTypeFormatter would have been used to deserialize and this entire process is seamless to the action method code, since it always receives the Employee object. This is one of the powerful features of the ASP.NET Web API.
Request Sent
POST /api/employees HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 49
{"Name":"John Q Law", "Department":"Enforcement"}
Response Received
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"Department":"Enforcement","Id":"123","Name":"John Q Law"}
Scenario 2: No Content Type
What if there is no content type specified in the request header? The ASP.NET Web API will not know what to do with the message. The web API returns 500 – Internal Server Error with a message that no MediaTypeFormatter is available to read the object of the type Employee with media type undefined.
Request Sent
POST /api/employees HTTP/1.1
Content-Length: 49
{"Name":"John Q Law", "Department":"Enforcement"}
Response Received
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8
{"ExceptionType":"System.InvalidOperationException","Message":"No 'MediaTypeFormatter' is available to read an object of type 'Employee' with the media type ''undefined''.","StackTrace":" at System.Net.Http.ObjectContent.SelectAndValidateReadFormatter(..."}
Scenario 3: XML Representation
If the content type is specified for XML and the XML representation of the resource is sent in the request message body then it starts to work again. The web API uses XmlMediaTypeFormatter, although this time around the resource sent back in the response also becomes XML.
Request Sent
POST /api/employees HTTP/1.1
Content-Type: application/xml; charset=utf-8
Content-Length: 80
<Employee><Name>John Q Law</Name><Department>Enforcement</Department></Employee>
Response Received
HTTP/1.1 200 OK
Content-Type: application/xml; charset=utf-8
<?xml version="1.0" encoding="utf-8"?><Employee xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Id>123</Id><Name>John Q Law</
Name><Department>Enforcement</Department></Employee>
Scenario 4: Mix and Match
It is possible to mix and match, that is, send the XML representation of the resource in the request body and ask for JSON to be returned or vice versa. If a web API is capable of handling the content type specified in the Accept header then it will send the resource in that representation. In the following example request, the client sends the request body as XML and indicates the same by specifying application/xml in Content-Type. However, the client prefers the response to be returned as JSON and indicates that preference by specifying application/json in the Accept header.
Request
POST /api/employees HTTP/1.1
Content-Type: application/xml; charset=utf-8
Accept: application/json
Content-Length: 80
<Employee><Name>John Q Law</Name><Department>Enforcement</Department></Employee>
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"Department":"Enforcement","Id":"123","Name":"John Q Law"}
The key point to note in this transaction is that the client asks and does not tell the server. If the Accept header of application/pdf, application/json is sent in the request then the ASP.NET Web API will not be able to send the response back as PDF, by default, and hence switches to the second choice, JSON. This process is therefore called Content Negotiation.
It is interesting to note that a web API switches to XML if the Accept header has just the application/pdf. It can't send a PDF for sure but there is nothing else specified as the second choice, so it switches over to the MIME type of the request, which is XML in this case.
4. Hypermedia as the Engine of Application State
The HATEOAS constraint requires a client to enter a RESTful service through a fixed URL. From that point onward, any future action a client takes will be based on what the client gets to discover within the resource representation returned by the service.
Let's take an example. A client makes a GET request to the resource with the identifier http://server/api/employees. In other words, the client is asking for a list of employees. As the next step, if the client needs to GET an employee, how will it go about doing it? One option is that the client "knows" it! Then, the client has to know quite a bit about the service. Another option is hypermedia, or hypertext. A service that satisfies the HATEOAS constraint returns not just data, but data and links.
In the previous example of the employee listing, each employee can have multiple links; one to look at employee details, or one perhaps to fire him, for example. Of course, the links available will be based on what the client is authorized to do. For a user who is not authorized to fire employees, there is no point in sending the firing link. Here is an example JSON representation of an employee resource with links.
Picture 4 - Hypermedia as the Engine of Application State
One obvious problem is what the client will do with the links. To get details, GET must be executed and for the next one, DELETE, probably, but how will the client know? The answer to the question is forms, which will contain all the necessary information for the client to make the next move.
HATEOAS is not supported by the ASP.NET Web by default if you expect a web API to provide links or forms intelligently without ever writing a line of code. However, it is possible to include them in the resource representation returned by writing your own custom code.
Thank you for reading this article, I hope you enjoyed it. Feedback and comments are highly appreciated. Follow for more!!