REST vs. RPC in ASP.NET Web API? Who cares; it does both.
ASP.NET, Web API By Dave Ward. Posted April 25, 2012It’s probably an understatement to say that ASP.NET Web API has sparked a bit of debate about RESTful design lately.
Web API’s new features like content negotiation, flexible media formatters, and improved JSON formatter are great, but they’ve been presented as features that are tied to the REST paradigm. That may seem troubling if you’re more accustomed to .NET’s RPC endpoints like ASMX, WCF, and even the way ASP.NET MVC controller actions are often used as a makeshift API.
A couple months after the new incarnation of Web API was announced, I’m still seeing a lot of confusion and unhappiness about Web API’s apparent push toward REST. However, what almost everyone has overlooked so far is that Web API supports RPC just as well as REST.
Over-simplifying the difference between REST and RPC
When I say REST, I don’t mean a peaceful afternoon napping in a hammock by the beach, but Representational State Transfer. A RESTful API exposes its data as resources (or nouns) at URIs that clients interact with via HTTP methods like GET and POST (or verbs).
On the other hand, remote procedure call (RPC) refers an API style where endpoints perform arbitrary actions, not necessarily tied to a particular resource. Typically, RPC service methods combine the noun and verb in one method name (e.g. GetPosts or SendInvoice). If you’re using ASMX or WCF today, you’re probably using the RPC approach.
In the context of ASP.NET Web API, the key distinction between REST and RPC is that in a RESTful approach your API consumers interact with public methods corresponding to HTTP verbs (e.g. Get() or Delete(int Id)). If a method doesn’t map to an HTTP verb, it doesn’t fit into a RESTful API.
ASP.NET Web API routing basics
Part of ASP.NET Web API’s magic is that it automatically routes requests to your API methods by convention, matching the request’s HTTP verb to a correspondingly named method in your API class.
For example, this default routing setup in the ASP.NET MVC 4 project template:
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
Means that you could write a class like this:
public class MyApiController: ApiController { public string Get() { return "Hello World"; } }
And then access that Get() method via HTTP by making a GET request to /api/myapi. Similarly, HTTP requests using the POST, PUT, and DELETE verbs would execute methods with names matching those verbs too.
No coloring outside the lines
That automatic RESTful routing is handy, but what if you wanted to add a method that doesn’t correspond to an HTTP verb, like good ‘ol FooBar:
public class MyApiController: ApiController { public string Get() { return "Hello World"; } public string FooBar() { return "FooBar"; } }
Confusingly enough, a GET request to /api/myapi/foobar returns Hello World instead of FooBar. The reason for that is because our default Web API route sends that request to MyApi with an {id} of FooBar and then Web API executes the Get() method since the request was an HTTP GET.
Web API supports RPC too
Easy REST support by convention is nice, but what’s not obvious in any of the samples I’ve seen is that Web API supports RPC-style routing too.
By adding an {action} parameter to the route, you can override Web API’s default HTTP verb-based routing:
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );
With this routing configuration, the previous GET request to /api/myapi/ returns a 404, but requests to /api/myapi/get via any HTTP verb return Hello World. That’s not incredibly useful by itself, but it means we can extend the API with arbitrary RPC methods now:
public class MyApiController: ApiController { public string Get() { return "Hello World"; } public string FooBar() { return "FooBar"; } }
Now, requests to /api/myapi/foobar will return FooBar instead of Hello World.
Gradually migrating from RPC to REST
Since “switching” from REST to RPC was just a routing change, it stands to reason that you could combine both approaches easily enough. Indeed, it’s as simple as using a pair of routes like these:
routes.MapHttpRoute( name: "RestApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "RpcApi", // I like "services" as the path prefix for this since it's // where I usually stored ASMX services in the past, but // you can use anything you want. "rpc" would be good too. routeTemplate: "services/{controller}/{action}" );
One important caveat with this approach is that you need to name your controllers carefully. Even if they’re in different namespaces, you’ll get an ambiguity error if both folders contain an API controller with the same class name.
It should be possible to resolve that issue by adding a constraint to the route, but I haven’t been able to get that working with MapHttpRoute. If you know how to make that work with Web API, please let me know.
Combining both REST and RPC
If you want to live dangerously, you can even mix both approaches in the same API controller. If you include an optional {action} parameter in your API route definition, you get Web API’s verb-based routing and the option to augment those basic methods with specified RPC-style methods.
routes.MapHttpRoute( name: "RestPCApi", routeTemplate: "api/{controller}/{action}", defaults: new { action = RouteParameter.Optional } );
Using the previous Get/FooBar class, making GET requests to /api/myapi/ return Hello World, while making a request via any HTTP verb to /api/myapi/foobar will return FooBar. Nifty.
I will say that I haven’t tried using this same-controller hybrid approach in any real code yet, so tread lightly (and please leave a comment on this post if you do try this with or without success).
Why bother? Isn’t REST better?
The prevailing popular opinion these days is clearly in favor of RESTful APIs. REST does make for a nice, clean API when it fits well. That’s especially true for relatively simple public-facing APIs (e.g. services like Twitter and Flickr), where everyone benefits from following common conventions.
On the other hand, private APIs sometimes don’t need a full CRUD implementation for every resource. When you only need a few combinations of noun and verb, a simple RPC API is a perfectly valid alternative to the cartesian product of nouns and verbs that a truly RESTful API requires you to implement.
More importantly, RPC routing support means you don’t need to be afraid of Web API, even if you’re heavily invested in ASMX or WCF services.
You can upgrade to Web API’s goodness without completely revamping your existing services (I recently updated one of my largest ASMX-based projects to ASP.NET Web API in less than a day using this RPC routing approach). That means you can maintain RPC support for those older services, while implementing new services in a RESTful style going forward, and migrate at your own pace without any of your services being stuck on a legacy technology.
Similar posts
What do you think?
I appreciate all of your comments, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to another comment, use the threading feature by clicking "Reply to this comment" before submitting your own.
2 Mentions Elsewhere
- Distributed Weekly 152 — Scott Banwart's Blog
- ASP.NET Web Api – apeluri RESTfull si RPC pentru aceeasi resursa



The issue I would see with this: routes.MapHttpRoute(
name: “RestPCApi”,
routeTemplate: “api/{controller}/{action}”,
defaults: new { action = RouteParameter.Optional }
);
is if you wanted a Get(int id) method as well. Looks like this would only be able to handle the Get(). Correct?
You could pass that through on the QueryString, for example:
Would make a request to
/api/myapi?id=1and that would route through correctly and pass theidparameter into aGet()method.Yes I tested that as well although….not a very “RESTFUL” URL though. ‘/api/myapi/5′ does not work for the purpose of hitting a method Get(int 5).
It definitely does require compromise to get both styles in the same controller. For my purposes, it’s the same either way since I’m usually consuming these things with jQuery, and I think it’s cleaner to use:
Instead of string concatenation:
I agree it is a pretty good compromise when you have control over both sides. I am not sure I would advise doing it on the Web API side if it was meant for public consumption, could be a bit confusing. Great post though!
Dave,
Actually, that is why id = RouteParameter.Optional is present. If you pass it an id value it will call Get(id), if you dont pass anything it will call Get()
Great Post Dave!! Question though..
Is there a benefit to include Web API in MVC applications ? Should I replace my MVC controllers that return JSON() or XML() with ApiControllers ?
I think the biggest advantage Web API has over MVC actions is that you’ll never need to think about using either the Json() or Xml() helpers. Web API uses content negotiation to automatically determine which serialization a given client prefers and responds accordingly. It also detects AJAX requests via the X-Requested-With HTTP header, so requests from jQuery (and most other client-side libraries) always get JSON.
Also, if you return an IQueryable, you get basic oData support automatically, which could be nice in some situations.
Plugging in new formatters, like JSONP, is easier (IMO) in Web API too.
Having the option to self-host it is nice too. You may never need to, but if you eventually wanted to move your API out of the MVC site, you could do that very easily if you’re using Web API.
There are probably other pros and cons I’m not thinking about. Anyone else want to jump in here?
One of the features that webApi is in relation to how async requests are handled. If you are on NET4.5 the WebApi against an async controller will pool threads rather than spin up new ones meaning a smaller server footprint is required for the same number of requests which can be as high as 100:1 saving.
Nice post Dave. Very useful and very pragmatic!!
Great post!
Sweet, lookig for rpc over mvc4 this helped me well! Thanks
Good article Dave, but I think that one of the things that is missing from this is the fact that REST is stateless whereas RPC is stateful. That’s where the major issue still lies within the .Net paradigm. Yes you can create REST services using WCF, but by in large if you look at Java’s implementation, all of this can be done within a web page without the necessity to have “running” services.
There has been discussion that SOA is moving more towards REST services and away from state driven due to the necessity for being language agnostic and stateless.
Other than that, still a really good article.
An endpoint like
UpdateInvoiceAmount(decimal Amount)is RPC, stateless, not RESTful, and quite common in private APIs that I’ve seen in the wild for client-side callbacks. That approach isn’t everyone’s preference, but I don’t think that’s necessarily “wrong” for a private API either. So, I think it’s good that Web API supports both.@Andrew – Not true, RPC does not inherently make a service stateful.
Example: A service exposing a method such as /api/securitytoken/new is an RPC call requesting the service to generate a new token for a calling system.
The service does not in any way track this token, it simply exposes a way for other systems to make use of the mechanism/algorithm for generating these tokens.
You could potentially make this RESTful by saying it should be /api/securitytoken/ and that this should be either a GET (i.e. GetNewToken()) or a POST (i.e. CreateNewToken()).
But to me, this token generation is a process, not a resource. I wouldn’t subsequently have the ability to delete or update a token. It’s a one off call.
How should I setup routing if I want to use the RestPCApi route and also a standard MVC controller, like in http://www.elylucas.net/post/MVC4-Quick-Tip-1%E2%80%93Put-your-API-Controllers-in-a-different-folder-to-avoid-class-naming-collisions.aspx
I figured it out by setting up the route’s namespaces
http://forums.asp.net/p/1772699/4847780.aspx/1?Re+How+do+I+set+the+default+namespaces+in+MapHttpRoute
Great post – thanks! I am actually doing something very similar in an application I am building as an MVC4 app. I am exposing the http functionality in a RESTful manner by using the neat routing that Web API provides, and simply supplementing it with routing for normal MVC actions – all in the same project. That way, I can build one application to serve as both the complete app as well as offer up the service via Web API routes. I like it!
Indeed a great post, I however humbly suggest you mist an combination of RPC en REST in the web api. I got the idea that you can use the two routes of the migration scenario and route them perfectly well into the same controller. the rest route will pick the functions with post, get, put and delete and the rpc route can pick any function. Only thing is that non-REST function cannot start their name with an http verb. This makes everything very neat and tidy.
Brilliant! I don’t know how many articles I read but something about your explanation of using routeTemplate: “services/{controller}/{action}” just clicked.
Writing an intranet app, REST is nice but sometimes I want an RPC command that might handle multiple steps etc.
I used “rpc” instead of services but it worked great! Really nice clear article which gave me that missing step in routing in MVC4 as I had gotten used to just RPC in MVC2 & MVC3 and didn’t pay a ton of attention.
Thanks!
This is pretty nice comparison, the way the routing for RPC and REST in the controller is explained simple and easy way.
Hi Dave,
routes.MapHttpRoute(
name: “RestApi”,
routeTemplate: “api/{controller}/{id}”,
defaults: new { id = RouteParameter.Optional }
);
You call this interface RESTful, my first question is, what is the resource in here?
If the resource is a controller, I would assume the id refers to the id of the controller and that methods like GET, POST, PUT, DELETE should apply to that resource (I will get a controller, I would create a new controller, I would update it or simply delete it). However, unless you have some kind of ‘controller’ database and what I explained is what you intended to exemplify, I think your examples are misleading. What you’re calling here REST may actually be a hidden RPC, cause you’re not talking about resources, but verbs. For example, calling “api/validator/0″ which maps to a dummy Controller ‘ValidatorController’ that validates whether a number is zero (extremely helpful I would bet), this could pretty much mean the same as calling “api/validate/0″ but with an explicit action through the Get method.
I think your main statement still stands:
“A RESTful API exposes its data as resources (or nouns) at URIs…”, though I disagree that only http methods like GET/POST are simply enough, this is a limitation by the browser and not by REST, pretty much as HTTP not being a requirement for it but the only protocol that is able to support it as for now.
In the basic sense that we want to separate verbs and nouns, I think coming up with RESTful interfaces that honor that basic principle is reaaaally hard sometimes.
Thanks!
The
{controller}parameter is essentially the name of the resource. So, thatMapHttpRouteregistration lets you have something like aPersonControllerthat has methods like these:So, then the resource is a
Person, not the controller itself.To me, the difference between this and a more RPC-style approach is that you’re respecting HTTP verbs to direct which method should be invoked. If you explicitly allow the
{action}to be specified in the URI, then you’re opting into what’s almost definitely not going to be a RESTful approach.Great Post!! Thank you!!