Why are there 2 controllers in the ASP.NET Web API ContactManager example? REST has ...
<some snarkiness follows/>
He then went on to further elaborate on the pedantic nature of the REST community and how his making a comment unleashed a religious war on the poor soul. At some point I was dragged in which then led to Rob, Darrel and I in a long but civil debate/discussion on Jabbr.
I am not going to defend the REST community and affirm or deny whether it is pedantic or not. That’s completely besides the point and it has zero to do with the sample.
In that post he then said:
“The developer who wrote those two Controllers will avidly defend them to me, citing Fielding and quoting Wikipedia.”
That developer just happens to be me. I won’t defend them on that basis. In fact, the decision to have two controllers had NOTHING to do with REST and nothing to do with any HTTP guideline.
It was a decision based on preference not based on keeping to some elite code.
Mainly separation of concerns. An item resource is semantically different from a collection resource. One handles an item, the other handles a collection. I could have handled both in the same class however I chose not to and felt that it was easier to test / maintain keeping them separate. I spoke to several folks at the time that also felt that keeping the separation made sense, so I left it the way that it was.
Why two URIs?
The other question one might ask “Why are there two base URIs, /contacts and /contact?” That’s a reasonable question.
Context, from an HTTP perspective, a URI is just an identifier, it can be anything. It doesn’t have to even make sense to the client, but there is nothing wrong if it does. For example, have you looked at your average MSDN page lately? I’ll bet your not going to memorize those URIs any time soon. Try this one on for size: http://msdn.microsoft.com/en-us/magazine/cc135976.aspx.
The first reason, is well because I could. Although it is very common to have base URIs for items and collections be the same, nothing forces you to do that because again it’s just an identifier. Speaking to various folks I found some preferred that it not be while many others thought it MUST be the same . In order to break that mental mold I chose to keep them separate.
The second reason was to illustrate how to keep the client decoupled from the server by leveraging some of what HTTP has to offer. By the conventional wisdom / using a single base URI, the client posts to “/contacts” and gets back a response which contains the new ContactID. The client then has logic to retrieve that ID and to append it to the base URI i.e. “/contacts/1” to get that contact. That however is flawed and won’t work in the ContactManager sample as the item is at a different base URI 😉
It’s not an issue though because fortunately HTTP provides an answer for us, the location header. If we put on our pedantic hats and head on over to the HTTP RFC we see the following:
“For 201 (Created) responses, the Location is that of the new resource which was created by the request.”.
201 is the status code returned from POST whenever a resource is created. When the server creates a resource it can also include a Location header indicating the URI where that new resource is located. For example if I post to “/contacts” the server can return me a location header of “/contact/1” to tell me where to find it.
It doesn’t have to have an ID in the URI though! It could be the name “/contact/glenn%20block”. It could be a guid i.e. “/contact/849bb2ff-ccff-4315-b2ea-4dcb9736b394”. It is completely up to the server and the contents of the URI may not even appear in the contact response itself. It doesn’t matter though. As long as my client is pedantic and follows the RFC all it has to do is save the location header URI and it can find that resource.
The beauty of this is that the server can evolve over time how it creates those URIs and the client is not broken. Oh no you are probably saying, here come the REST zealots!
Hardly. For example (kudos to @howard_dierking for this scenario) imagine initially when we created our system we used long IDs in the URI that point to each contact. Then over time we realize we need to scale out and replicate across servers. At that point we need an ID that is unique across all DB instances, such as a GUID. We can now silently change the contact URI to use a GUID instead. Our clients happily operate without a hitch as they simply take the newer URI that is handed to them in the location header.
I hope this clarifies why we have 2 controllers which itself has nothing to do with REST.