Build truly RESTful API and website using same ASP.NET MVC code

A truly RESTful API means you have unique URLs to uniquely represent entities and collections, and there is no verb/action on the URL. You cannot have URL like /Customers/Create or /Customers/John/Update, /Customers/John/Delete where the action is part of the URL that represents the entity. An URL can only represent the state of an entity, like /Customers/John represents the state of John, a customer, and allow GET, POST, PUT, DELETE on that very URL to perform CRUD operations. Same goes for a collection where /Customers returns list of customers and a POST to that URL adds new customer(s). Usually we create separate controllers to deal with API part of the website but I will show you how you can create both RESTful website and API using the same controller code working over the exact same URL that a browser can use to browse through the website and a client application can perform CRUD operations on the entities.

I have tried Scott Gu’s examples on creating RESTful routes, this MSDN Magazine article, Phil Haack’s REST SDK for ASP.NET MVC, and various other examples. But they have all made the same classic mistake – the action is part of the URL. You have to have URLs like http://localhost:8082/MovieApp/Home/Edit/5?format=Xml to edit a certain entity and define the format eg xml, that you need to support. They aren’t truly RESTful since the URL does not uniquely represent the state of an entity. The action is part of the URL. When you put the action on the URL, then it is straightforward to do it using ASP.NET MVC. Only when you take the action out of the URL and you have to support CRUD over the same URL, using three different formats – html, xml and json, it becomes tricky and you need some custom filters to do the job. It’s not very tricky though, you just need to keep in mind your controller actions are serving multiple formats and design your website in a certain way that makes it API friendly. You make the website URLs look like API URL.

The example code has a library of ActionFilterAttribute and ValurProvider that make it possible to serve and accept html, json and xml over the same URL. A regular browser gets html output, an AJAX call expecting json gets json response and an XmlHttp call gets xml response.

You might ask why not use WCF REST SDK? The idea is to reuse the same logic to retrieve models and emit html, json, xml all from the same code so that we do not have to duplicate logic in the website and then in the API. If we use WCF REST SDK, you have to create a WCF API layer that replicates the model handling logic in the controllers.

The example shown here offers the following RESTful URLs:

  • /Customers – returns a list of customers. A POST to this URL adds a new customer.
  • /Customers/C0001 – returns details of the customer having id C001. Update and Delete supported on the same URL.
  • /Customers/C0001/Orders – returns the orders of the specified customer. Post to this adds new order to the customer.
  • /Customers/C0001/Orders/O0001 – returns a specific order and allows update and delete on the same URL.

All these URLs support GET, POST, PUT, DELETE. Users can browse to these URLs and get html page rendered. Client apps can make AJAX calls to these URLs to perform CRUD on these. Thus making a truly RESTful API and website.

Customers

They also support verbs over POST in case you don’t have PUT, DELETE allowed on your webserver or through firewalls. They are usually disabled by default in most webservers and firewalls due to security common practices. In that case you can use POST and pass the verb as query string. For ex, /Customers/C0001?verb=Delete to delete the customer. This does not break the RESTfulness since the URL /Customers/C0001 is still uniquely identifying the entity. You are passing additional context on the URL. Query strings are also used to do filtering, sorting operations on REST URLs. For ex, /Customers?filter=John&sort=Location&limit=100 tells the server to return a filtered, sorted, and paged collection of customers.

Read my CodeProject article for details:

http://www.codeproject.com/KB/aspnet/aspnet_mvc_restapi.aspx

The source code is available here:

http://code.msdn.microsoft.com/Build-truly-RESTful-API-194a6253

Enjoy!

Create ASP.NET MVC Controllers under Namespace and specific URL

When you have a lot of controllers, you need to organize them
under Namespaces. Also, it is better to put controllers under
subfolders in order to organize them properly and have some
meaningful URL for them like /Admin/User where Admin
is the subfolder and User is the controller. For example,
you might have a lot of controllers that are APIs exposed by your
web app, not regular pages. So, you might want to put them under
/API/ folder. You also want to make sure no one can access
those controllers from the root url. For example, no one must call
/User/GetUserList instead they must call
/API/User/GetUserList

ASP.NET MVC default routing and Controller Factory is very
greedy, it ignores the subfolders inside the “Controllers” folder.
There’s a DefaultControllerFactory class in ASP.NET MVC
which traverses all controllers under the “Controller” folder and
creates a cache using just the class name as the key. So, it
ignores any namespace or any subfolder where you have put the
controller. So, I created a derivative of the default controller
factory and created a new factory that checks if the requested
controller belongs to any specific namespace and whether that
controller must be inside a specific subfolder. You can map
/Admin folder to respond to all controllers that are under
then YourWebApp.Admin namespace. Similarly, you can map
/API folder to respond to all controllers that are under the
YourWebApp.API namespace. None of these controllers can be
accessed outside the specified URL. Here’s the factory that does
it:


ProtectedNamespaceController Factory that replaces DefaultControllerFactory

This controller checks the namespace of the controller being
returned by ASP.NET MVC’s default implementation and ensures the
requested URL is the right url where controllers from the namespace
can be accessed. So, this means if the controller matches
MvcWebAPI.API.UserController, it ensures the URL being
requested must be /MvcWebAPI/API/User. It will return null
if the URL was something else like /MvcWebAPI/User or
/MvcWebAPI/SomeotherFolder/User.

Here’s how you use it form Global.asax:


Using ProtectedNamespaceControllerFactory from Global.asax

You create a mapping for a Namespace and the subfolder it must
belong to. Then you register the new Controller Factory as the
default controller factory.

Now the second catch is, the default Route for the
{controller}/{action}/{id} won’t work for you. You need to
create a specific router that starts with the subfolder name. For
example, API/{controller}/{action}


Creating a new route for the Controllers under the /API folder

Here’ two things to notice:

  • The use of PathStartWith routing constraint, which I
    will explain soon
  • The last parameter which tells the route to include the API
    namespace for this route. Otherwise it can’t find the controllers
    in the API namespace

So, the PathStartsWith routing constraint ensures this
route gets hit only when the requested URL is under the
/API/ folder. For any other URL, it returns false and thus
the routing handler skips this route.


image

It just does a comparison on the AbsolutePath of the
current request URL to ensure the URL starts with the specified
match.

Similarly, we need to tell the Default route to ignore all paths
with /API. Here’s how to do it:


image

That’s it. Enjoy the full code from:

http://code.msdn.microsoft.com/MvcWebAPI

Read my previous post on creating Web API using ASP.NET MVC that
can consume and expose Json and Xml:


Create REST API using ASP.NET MVC that speaks both Json and plain
Xml

Note: incase you already read it, I have published new code that
you should download.

kick it on DotNetKicks.com

Create REST API using ASP.NET MVC that speaks both Json and plain Xml

UPDATE: There’s a newer article on this that shows how to create a truly RESTful API and website using the same ASP.NET MVC code.

www.codeproject.com/KB/aspnet/aspnet_mvc_restapi.aspx

ASP.NET MVC Controllers can directly return objects and collections, without rendering a view, which makes it quite appealing for creating REST like API. The nice extensionless Url provided by MVC makes it handy to build REST services, which means you can create APIs with smart Url like “something.com/API/User/GetUserList”

There are some challenges to solve in order to expose REST API:

  • Based on who is calling your API, you need to be able to speak both Json and plain old Xml (POX). If the call comes from an AJAX front-end, you need to return objects serialized as Json. If it’s coming from some other client, say a PHP website, you need to return plain Xml.
  • Similarly you need to be able to understand REST, Json and plain Xml calls. Someone can hit you using REST url, someone can post a Json payload or someone can post Xml payload.

I have created an ObjectResult class which takes an object and generates Xml or Json output automatically looking at the Content-Type header of HttpRequest. AJAX calls send Content-Type=application/json. So, it generates Json as response in that case, but when Content-Type is something else, it does simple Xml Serialzation.

image

Here’s the ObjectResult that you can use from Controllers to return objects and it takes care of proper serialization method. Above shows the Json serialization, which is quite simple.XmlSerialization is a bit complex though:

image

Things to note here:

  • You have to force UTF8 encoding. Otherwise it produces UTF16 output.
  • XML Declaration is skipped because that’s not quite necessary. Wastes bandwidth. If you need it, turn it on.
  • I have turned on indenting for better readability. You can turn it off to save bandwidth.

Some of you might be boiling inside looking at my obscure coding style. I love this style! I am spoiled by jQuery. I wish there was a cQuery. I actually started writing one, but it never saw day light just like my hundred other open source attempts.

Now back to Object Serialization, we got the serialization done. Now you can return objects from Controller easily:

image

You can use the test web project to call these methods and see the result:

image

So far you have seen simple object and list serialization. A best practice is to return a common result object that has some status, message and then the real payload. It’s handy when you only need to return some error but no object or list. I use a common Result object that has three properties – ErrorCode (0 by default means success), Message (a string data type) andData which is the real object.

image

When you want to return only a result with error message, you can do this:

image

This produces a result like this:

image

No payload here. So, the return format is always consistent. Those who are consuming service can write a common Xml or Json parsing code to consume both success and failure response. Those who are building API for their website, I humbly request you to return consistent response for both success and failure. It makes our life so easier.

So, far we have only returned objects and lists. Now we need to accept Json and Xml payload, delivered via HTTP POST. Sometimes your client might want to upload a collection of objects in one shot for batch processing. So, they can upload objects using either Json or Xml format. There’s no native support in ASP.NET MVC to automatically parse posted Json or Xml and automatically map to Action parameters. So, I wrote a filter that does it.

image

This filter intercepts calls going to Action methods and checks whether client has posted Xml or Json. Based on what has been posted, it uses DataContractJsonSerializer or simpleXmlSerializer to convert the payload to objects or collections.

You use this attribute on Action methods like this:

image

The attribute expects a parameter name where it stores the deserialized object/collection. It also expects a root type that it needs to pass to the deserializer. If you are expecting a single object, specify typeof(SingeObject). If you are expecting a list of objects, specify an array of that object like typeof(SingleObject[])

You can test the project live at this URL:

http://labs.dropthings.com/MvcWebAPI

The code is also available at:

http://code.msdn.microsoft.com/MvcWebAPI

Enjoy!

————

Here’s an Eid gift for my believer brothers. Check out this amazing sitewww.quranexplorer.com/. You will get online recitation, translation – verse by verse. The recitation of Mishari Rashid is something you have to listen to to believe. Try these two recitations to see what I mean:

Sura 97 – Verse 1
Sura 114 – Verse 1

Press the “Play” icon at bottom left (hard to find).

kick it on DotNetKicks.com