Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Everything about REST web services - what and how - Part 2 - design

4.82/5 (75 votes)
10 Nov 2007CPOL16 min read 4  
This article is Part 2 in my series on REST web services. While the first article introduces REST web services, this one takes us through the process of designing a RESTful web service

Steps of designing a REST-ful web service


Bringing together the pieces of the puzzle

In my earlier article, I introduced the concept of REST web services. Before rushing on to how to implement or code a REST web service, first we have to stop at the design station. I know many developers who are more eager to start coding before spending some time on a proper design. Somehow they overlook the fact that you do not need Visual Studio to design; a whiteboard is sufficient.

Given a web service requirement, the first step of REST design is to determine the objects we will expose and their respective representations. An object's representation can be thought of as its set of properties. Representation needs to be designed carefully, and we will soon see about that.<o:p>

Let us try to build on the classic example of Employee Management. Imagine a web service aiming to expose an employee management interface. This is a good start because the object to expose is easy to agree upon – employee. Remember, in REST, we expose objects and not methods.

<o:p>The next step is to nail down the representation of the object – how about a simple XML structure sufficient for our example:

<o:p>

<Employee id='25648'>
    <Name>Peter Scheufele</Name>
    <Address>123 Main St. Dallas TX 75226</Address>
    <Designation>System Analyst</Designation>
    <HireDate>08/20/2007</HireDate>
</Employee>

Here, I need to stress on a few vital points about what representation really means and how it should be designed. To let me do that, let us examine the concepts of resource and URI.<o:p>

In the era of customer service, the biggest drive for REST web services is that it is supposed to make it easy for the clients. How much easier does it get for clients if they directly type in the object they want to operate on, in the URL?

Imagine an HR associate wanting to view employee Peter Scheufele's details – and she typing in

<o:p> http://employeeinfo/v1.4/employee/12098

<o:p>in her browser's address bar! She has to know that 12098 is Peter's Employee Id. Even if she does not know that, how about the URL:

<o:p> http://employeeinfo/v1.4/employees?name=peter

<o:p> and get back a list of employees whose names have "peter" in them?

<o:p>

Note the words employee and employees in the two URLs above. They are the resources. Resources are the objects exposed by the REST web service and accessed using the URL itself. In this example, the web service exposes two objects – employee, representing 1 employee, and employees, representing the collection of employees. Instead of being an URL, these addresses above are, truly speaking, URI-s. Because they do a little bit more than locate a resource, they actually identify a resource. That is why these are uniform resource identifiers. <o:p>

The representation of a resource should be thought as the state of a resource. If the representation changes, it is an UPDATE operation on that resource. The representation is typically returned in response to a GET. We made the representation of employee object an XML. Must it be XML? No. It can be anything, but XML is hard to beat. Good REST web services also support JSON along with XML, but let us stick to XML for a while as we clear up the basics. <o:p>

Returning to HTTP verbs, REST sets up a rudimentary guideline: what should a web service do in reaction to the HTTP verbs GET, PUT, POST and DELETE? Here are the guidelines: <o:p>



  • GET: Return (retrieve) the representation of the resource identified on the URI

<o:p> Example:

<o:p> Client --> Server: Client calls our web service to get the details of Peter Scheufele:<o:p>

GET http://employeeinfo/v1.4/employee/12098 HTTP/1.1
Accept: */*
Accept-Language: en-us
Authorization: hisyi76985==03784j3bkngdfyuwetfiuw
User-Agent: Client Application developed by the super coders
Host: supercoders
Connection: Keep-Alive

<o:p>
<o:p>Server --> Client: Server responds with Peter Scheufele's representation:<o:p>

HTTP/1.1 200 Ok
Server: Apache-Coyote/1.1
Last-Modified: Thu, 11 Oct 2007 14:45:35 GMT
ETag: 12098
Location: <a href="http://employeeinfo/v1.4/employee/12098">http://employeeinfo/v1.4/employee/12098</a> 
Date: Fri, 12 Oct 2007 12:00:28 GMT
Connection: Close
Content-Type: text/xml; charset=UTF-8
Content-Length: 2324

<Employee id='12098'>
    <Name>Peter Scheufele</Name>
    <Address>123 Main St. Dallas TX 75226</Address>
    <Designation>System Analyst</Designation>
    <HireDate>08/20/2007</HireDate>
</Employee>

<o:p>Notes: Note that the request does not have a HTTP body, but the response contains the Peter Scheufele's representation as the HTTP body, and it sets some specific HTTP headers to certain values – these being REST's best practices.<o:p>



  • PUT: Update the representation of the resource identified on the URI

<o:p>Example:<o:p>

<o:p>Client --> Server: Client calls our web service to update Peter Scheufele's address:<o:p>

PUT http://employeeinfo/v1.4/employee/12098 HTTP/1.1
Accept: */* 
Accept-Language: en-us
Authorization: hisyi76985==03784j3bkngdfyuwetfiuw
User-Agent: Client Application developed by the super coders
Host: supercoders
Connection: Keep-Alive
Content-Type: text/xml; charset=UTF-8
Content-Length: 354

<Employee id='12098'>
    <Address>6777 Spring Creek Dr. Fairview TX - 56458</Address>
</Employee>

<o:p>Server --> Client: Server updates Peter Scheufele's address and responds with Peter Scheufele's representation:<o:p>

HTTP/1.1 200 Ok
Server: Apache-Coyote/1.1
Last-Modified: Thu, 11 Oct 2007 14:45:35 GMT
ETag: 12098
Location: <a href="http://employeeinfo/v1.4/employee/12098">http://employeeinfo/v1.4/employee/12098</a> 
Date: Fri, 12 Oct 2007 12:00:28 GMT
Connection: Close
Content-Type: text/xml; charset=UTF-8
Content-Length: 2214

<Employee id='12098'>
    <Name>Peter Scheufele</Name>
    <Address>6777 Spring Creek Dr. Fairview TX - 56458</Address>
    <Designation>System Analyst</Designation>
    <HireDate>08/20/2007</HireDate>
</Employee>

<o:p> Notes: Note that the request sends in the employee representation XML as the HTTP body, but interestingly, it only sends the information that needs to be updated. This is not part of any guideline – it is up to you, the designer of the web service, to dictate – whether you expect client to send the entire representation XML on update, or just the elements that need to be updated. A well-architected system will usually use a XSD to validate the incoming XML, so the XML schema needs to be designed such that it allows incremental update XML-s. Here we have significantly deviated from pure REST discussion, because these deliberations are application specific design, but I thought these are necessary to highlight the practical aspects of REST.<o:p>

Note that the response carries with it the entire representation of Peter Scheufele, this being a REST best practice. When a resource's representation is updated, the web service should send the entire representation back to client on successful update. Again, this is not a "cannot-violate" rule, just recommended.


The other two verbs: POST and DELETE

Now that we have seen GET and PUT in action, it is time to deal with POST. Before diving deep into POST, let us quickly look back at the definitions of GET and PUT, already stated above once:<o:p>

GET: Return (retrieve) the representation of the resource identified on the URI

PUT: Update the representation of the resource identified on the URI<o:p>

Notice how both these verbs act on the resource's representation? Do you recall the high level objective of REST explained in the previous article? The whole idea of a few standard verbs acting upon exposed nouns? We see exactly that happening here: GET and PUT just acted on the resource employee/12098 in a standard, predefined manner: GET retrieved it, PUT updated it.<o:p>

To be more technically correct, GET retrieved the representation, PUT updated the representation. Thus, we now have a clearer picture of what a representation is: it acts as the alias of the resource – the part that HTTP verbs actually act upon.<o:p>

Having said that, let us turn to POST. In Rest, POST means create a new resource. Can you visualize such a request acting upon the representation of some existing resource? How is that possible?<o:p>

Thus, if the client does a POST to http://employeeinfo/v1.4/employee/12098, is that meaningful? Obviously not – because the new resource to be created is not related to 12098 (Peter Scheufele).<o:p>

What if the POST comes to http://employeeinfo/v1.4/employee? Well – though that is a little bit more meaningful, still we are having difficulty to enforce the rule – a REST request should act on the representation of the resource identified by the URI. First of all, the URI here does not identify any particular employee, and there is no representation of just employee.<o:p>

This is exactly where the necessity of a collection resource arises. We did, briefly, mention a collection resource when we were visualizing an HR employee fiddling with REST.<o:p>

A collection resource has its own representation, and is characterized by the fact that it does not need any specific instance to be accessed. Let us, for our web service, expose the second object:<o:p>

employees<o:p>

Being just the plural form of employee, employees is a collection resource with the following representation:
<o:p>

<Employees>
    <Employee id='12098'>
        <Name>Peter Scheufele</Name>
        <Address>6777 Spring Creek Dr. Fairview TX - 56458</Address>
        <Designation>System Analyst</Designation>
        <HireDate>08/20/2007</HireDate>
    </Employee>
    <Employee id='58585'>
        <Name>Tina Sreenivas</Name>
        <Address>324 Valley View Rd. Anna TX - 75848</Address>
        <Designation>HR Analyst</Designation>
        <HireDate>01/10/2005</HireDate>
    </Employee>
    <!-- Multiple Employee element supported -->
</Employees> 

It is not necessary to use the plural as the name of a collection resource – we can call it EmployeesColl or AllEmployees or whatever. Also, if the individual representation of each employee is too large, it may be impractical and performance degrading to pack the entire representation of each employee inside employees. In that case, we can define the representation of employees as follows:<o:p>

<Employees>
    <Employee id='12098'>
    <a href="http://employeeinfo/v1.4/employee/12098">http://employeeinfo/v1.4/employee/12098</a>
    </Employee>
    <Employee id='58585'>
    http://employeeinfo/v1.4/employee/58585
    </Employee>
    <!-- Multiple Employee element supported -->
</Employees>

<o:p>

This representation simply packs the URI-s of each employee in the collection instead of the full representation of each employee. The client then would need to issue GET commands for each employee (on their respective URI-s) to get the individual data back.<o:p>

Note that the exposed object employees does not need any specific employee id to be specified – hence it can be thought of as a global resource. If client does a GET on employees, it will look like:

GET http://employeeinfo/v1.4/employees HTTP/1.1

<o:p>The response will contain the entire representation of employees, containing all the employees in it.<o:p>

In REST, you can also define your own query string parameters. You can expose a search functionality using a combination of GET and the resource employees. For example, you could support query string parameters name and address. In response, the representation XML that you return might contain only those employees which satisfy the search criterion. For example:<o:p>

GET http://employeeinfo/v1.4/employees?name='george' HTTP/1.1

<o:p>The above request will return a list of all employees whose name has "george" in it.<o:p>

Suddenly, a whole new set of infinite possibilities are opening up – aren't they? With a clever combination of resources that you define, their representation that you design, and the query string parameters that you devise – the world is yours to conquer! While a traditional web service's methods provide a drab dull unilateral dimension of exposing your functionality – REST provides you with an array of interesting components to permute and combine into a dazzling array of services – all within the framework of standardized HTTP verbs and their standardized meanings.<o:p>

Getting excited about it? Let us return to POST. You have probably already guessed it – the POST verb, in our example, should be allowed only on employees resource.<o:p>

Thus, the request:<o:p>

POST http://employeeinfo/v1.4/employees HTTP/1.1

<Employee id=''>
    <Name>Bruce Evans</Name>
    <Address>1 ABC Rd. OK - 85748</Address>
    <Designation>Assistant Manager</Designation>
    <HireDate>11/12/2007</HireDate>
</Employee>

Is requesting the creation of a new employee – Bruce Evans. And note how that follows the REST guideline - a REST request should act on the representation of the resource identified by the URI. Are we following this guideline? To the letter! Look how: what is the resource identified in this URI? Employees. What is its representation? The XML containing all the employee elements. This request acts on that representation, because it creates another employee node at the end.<o:p>

A few points to note about this POST request: It is not sending in the employee id in the request XML, because the new employee is not yet created. It has to pass in enough information so that the service can create a new employee. And the response may either return the representation of employees with only the newly created employee in it, or it may return the representation of the newly created employee. The response should have the id of the new employee in it. The response should carry the HTTP response code 201 Created (and not 200 Ok).<o:p>

The DELETE verb is used to delete a resource. Now that we have two resources: employee and employees, DELETE can act on either, but in order to act on employees, it has to specify which employee to delete, which it can do by a query string id. Thus:<o:p>

DELETE http://employeeinfo/v1.4/employees?id=45125 HTTP/1.1
And<o:p>
DELETE http://employeeinfo/v1.4/employee/45125 HTTP/1.1

Both should be treated equivalently. As designer, you can restrict the delete operation to only one of these – you may choose to say that DELETE should only be sent to employee resource. That will save you from adding yet another query string parameter id.<o:p>


Output of design

The output of our design so far is what I call an action matrix. It lays down, as a grid, how our web service reacts to different requests - which are combinations of the HTTP verbs, URI-s, query string parameters, etc.<o:p>

VerbURIQuery StringRequest BodyResponse CodeResp BodyOther Remarks
GET…/employee/{id}ignoredignored200 OkERX404 Not Found response if id does not exist
PUT…/employee/{id}ignoredERX200 OkERXPartial ERX OK in input
POST…/employee/{id}ignoredignored405 Not Allowederror XMLPOST forbidden on this URI
DELETE…/employee/{id}ignoredignored200 Okempty404 Not Found response if id does not exist
GET…/employeeignoredignored400 Bad requestemptyGET must specify employee id in URI
PUT…/employeeignoredignored400 Bad requestemptyPUT must specify employee id in URI
POST…/employeeignoredERX201 CreatedERXNew employee will be created if data is sufficient in request ERX. Else 400 response.
DELETE…/employeeignoredignored400 Bad requestemptyDELETE must specify employee id in URI
GET…/employeesname, address, idignored200 OkESRXAll employees returned if no query string param. Search result returned if query string.
PUT…/employeesignoredignored405 Not Allowederror XmlPUT not allowed on employees URI
POST…/employeesignoredERX201 CreatedESRXNew employee will be created if data is sufficient in request ERX. Else 400 response.
DELETE…/employeesidignored200 Okempty404 response if bad id, 400 if id param missing

ERX = Employee Representation XML, ESRX = Employees Representation XML.<o:p>

I have not included a column that explains the operation - which would have said "Updates employee data" for the first PUT record - the space constraint of drawing an HTML table is very annoying. Thus, this table defines the behavior of our web service. You can say, this is the REST equivalent of the WSDL - the contract! This is what the designer passes on to developers of both the service and the client. And trying to figure this matrix out for your specific web service need is what this article is about - REST design.<o:p>


REST does not enforce a lot

Now that we have designed a simple REST web service, it is time to tell you that we have used a few concepts that REST does not necessarily enforce. For example, we created a collection resource because POST to an employee resource does not make sense. But as a web service designer, you could have said, "I don't care". You can write your web service in such a way that new employee creation must be done by posting to employee. Thus, consider a request like the following:<o:p>

POST http://employeeinfo/v1.4/employee HTTP/1.1

<Employee id=''>
    <Name>Bruce Evans</Name>
    <Address>1 ABC Rd. OK - 85748</Address>
    <Designation>Assistant Manager</Designation>
    <HireDate>11/12/2007</HireDate>
</Employee>

That might a valid legitimate request for your web service, and there is nothing overtly wrong with that. It does slightly violate the REST rule that a REST request should act on the representation of the resource identified by the URI. But this is like bending the rule a little bit.<o:p>

I have seen a lot of web services bending rules like that – and nobody is sad. As long as it makes sense to clients, as long as it does not violate the basic tenets of the HTTP verbs: GET is retrieval, PUT is updating, POST is creation and DELETE is deletion, any REST design is OK. The perfect design, according to me, will, however, try to follow the best practices guidelines and not bend any rules.<o:p>

Thus, the bottom line is your definition of the resources (objects), your construction of the URI-s and the representation-s, and your final action matrix: which verb applied to which URI along with what query string parameters result in what action – is all what is REST design is about.<o:p>


Complex actions

So far, the REST web service we have designed can effectively replace a traditional web service with the following web methods:<o:p>

GetEmployeeInfo, SetEmployeeInfo, AddEmployee and DeleteEmployee.

Now, say the traditional web service also has another method –

'TransferEmployee'

How will we implement it in REST? Whenever we face a situation like this, we should ask ourselves: does this action change the representation of the resource? Well, does it? In this case, answer is: yes it does, only if the representation contains location. That results in modification of our representation XML – we will add location to it. And we will use the PUT verb to implement TransferEmployee. Because now TransferEmployee becomes a simple update call – it is nothing but updating the representation with a new location.<o:p>

Sometimes it becomes a tad difficult to answer the question – does this action change the representation? Because some operations seem to be such that they don't really appear to change any properties. Let us imagine a web service for lending decisions. If you walk into a bank asking for an automobile loan, the banker, in most cases submits the approval request to a centrally hosted decision maker which all the bank branches use. Let us imagine this to be a web service. Let us imagine a traditional web service with the method GetLoanApprovalDecision – this being the web method that the clients running on the bankers' machines call. How will we model a REST web service to do this very job?<o:p>

Here, the design challenge is to give the right amount of turns to our rubik's cube's sub-cubes – we have resources, URI-s, representations and query string parameters as our raw materials.<o:p>

Our web service might have customer as a resource – but will that help us to model GetLoanApprovalDecision? Not much. How about having the resource loan? Will that help us create a representation which we can refer when we ask – does GetLoanApprovalDecision change this representation? Or, will application be a better resource to expose?<o:p>

There are no rights or wrongs – only betters and worses. I would go for application resource – with the representation XML containing the personal data of the applicant and a section called Status. The request will leave it blank, and the response will fill it up with "Approved" or "Declined" or "Referred to underwriter". I would use POST to create a new application. The creation request will return an application id. After creation, I would support a GET on a specific application resource to get the status. That would be my equivalent of GetLoanApprovalDecision – notice that I have split it up into 2 REST calls – POST and GET. The POST creates an application resource, the GET retrieves the status. I could also have a query string parameter view that will be supported by GET, with possible values all, applicant and status. While the response to "all" will return the entire representation XML, "applicant" will return only the sub-node that contains the applicant data, and "status" will return the loan approval/ decline decision part. Thus, here is what my REST equivalent of GetLoanApprovalDecisionlooks like:<o:p>

<o:p>

Call 1:

POST http://mybank.loans.com/v2.0/loanapplication HTTP/1.1
<application>
    …
</application>

Response to call 1 returns the representation XML of loan application resource containing the application id. Say the id generated is 546. In that case, call 2 will be:

Call 2:

GET http://mybank.loans.com/v2.0/loanapplication/546?view=status HTTP/1.1

Conclusion

In the next and last part, we will touch upon implementation. We will create a REST web service and the corresponding REST client – in .NET 2.0. Yes, you heard right - .NET 2.0. Microsoft released the .NET 2.0 platform fully geared for SOAP, and when they sensed the growing urgency for REST support, they begun spraying in REST support in 3.0 - and the promised 3.5 version is nothing but REST! But in spite of lack of support, you can still develop a REST web service in .NET 2.0. I will try to elaborate on that in the next article. That will conclude this series on REST web services.<o:p>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)