Web Api REST Routes and REST

I have been working with Web Api for a number of months.  When I switch to version 2, I switched to attribute based routes.  In addition to the reasons specified in the article, there is one more reason why I wanted to use the attribute based routes.  They provided a very easy and convenient way to generate documentation using SandCastle to give to our customers.  In addition, it makes it easier to maintain the code, as you can just look at the controller class and know for sure what URL is used for what route.  For all complex routes you need to look at the method anyway, and having the route explicitly stated is an advantage.  After this, I wanted to talk about my philosophy in assigning routes for business applications that use Web Api that follow the spirit of REST.  We are talking about HTTP verbs, business operations and entity operations.

REST approach has a number of constraints that are put onto routes (read Uri’s).  Each Uri should uniquely identify a resource as well as operations on that recourse. For example, if I want to have a path to a person with a unique id of 1, I would have something similar to http://mysite.com/persons/1.  If you look at this Uri, it breaks down into two segments – collection that a person belongs to and a unique id of the person.  So, we are on par with REST so far.  Of course, sometime you need to perform an operation on a person.  Typically, you need to support CRUD operations – create, retrieve, update and delete.  Now, REST, staying in compliance with HTTP standards, dictates that you should do the following:

Create: http://mysite.com/persons with POST method and the person JSON contained within the body of the HTTP message.  The reason we do not include Id is because Id could be created by the server.

Retrieve: http://mysite.com/persons/1 with GET method

Update: http://mysite.com/persons/1 with PUT method and the person JSON contained within the body of the HTTP message.

Delete: http://mysite.com/persons/1 with DELETE method with nothing in the body.  Of course, what if you want to include concurrency column?  Then, I would include person object as JSON in the body, at least with properties you need to perform the delete.

 

How about other functions?  What if you want to get the list of people?

Then I would use http://mysite.com/persons with GET method.  What if you need to have criteria, such as partial name, page number and number or rows per page?  Then I would include criteria into the body of the message as a JSON representing criteria class.  In general, I would submit primitive criteria, such as just name as Uri query string parameters and complex criteria as JSON in the body of the message.  However, as I did more research, it is not customary to have a body in the get method.  So, the only option is to send it with a POST.

So, if I need to get all the people based on partial name, I would have

http://mysite.com/persons?name=blah with GET method and empty body.

If I need to include more complex criteria, I would have

http://mysite.com/persons with POST method and body containing {“name”: “blah”, “page”: 1, “rowsPerPage”: 10, “sortBy”: “lastName”, etc…}

I am on the fence with this still, but I do not want to run into or alter server that allow limited size of the query string.  For example, IIS allows by default 2K.  What if I am sharing the server and the admin will not allow me to alter this setting?  Of course, I can always alter it just for my app in config file.  But then, I am reducing the safety of my URLs, allowing users to post arbitrary size GET messages.  So, I do not like any answers, but I will go with the POST, as it seems safer than the alternative.

 

How about non CRUD operations?  In all complex business apps you always have RPC (remote procedure calls) style calls you need to support through Web Api.  For example, you want to update all active persons with certain names and set their last interview dates to something and maybe insert some child records and maybe update history.  In those cases I standardize on the following

 

http://mysite.com/persons with POST method and RPC parameters following the GET rules above: simple criteria parameters in the URL, complex criteria object in the body.

How about even more complex scenarios?  Say you want to insert a child record, maybe a note, for a person?  If you read the standards, that should translate into

http://mysite.com/persons/1/notes with POST method, containing new note in the body.

This represent a problem though.  In typical business applications there are more complex rules.  A few come to mind.  For example, you have concurrency implemented on the person.  So, now you need to technically update a person, which translates into PUT method.  Now, we are in lose-lose situation.  No matter which route you go, you are technically going to be “wrong” from a REST  HTTP purist perspective.  So, I like to simplify my story and go with CRUD rules.  So, whether I update a person or insert a person note, I will follow update person rules.

 

I am certain, that a large number of people do not agree with what I described here, but I find that this approach is mostly in line with REST spirit an HTTP standards, while being simple and easy to understand as well as easy to use in your web application.  Let me know what you think.

4 Comments

    • i hae looked at that article, great one, configured the same way, but $http.post (POST) request in angular is being converted to OPTIONS, so the backend webapi controller cannot understand options. says not allowed method. would be glad if you provide same basic start to end example of doing this

Leave a Reply to evc Cancel reply

Your email address will not be published. Required fields are marked *