WebAPI Routing and Custom Get Methods
The default structure of the routing we are using for our Web API service layer is set up to take an integer or a guid as the id for GET requests. This is done because it is a best practice when creating a database to have the primary key as an integer or guid. In our routing this is implemented with this default route:
config.Routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"^{?[dA-Fa-f]{8}-[dA-Fa-f]{4}-[dA-Fa-f]{4}-[dA-Fa-f]{4}-[dA-Fa-f]{12}}?$|d+" });
If an id is specified then the route uses a regular expression to allow only an integer or guid as the id parameter. This is important not only because it is a best practice but also because it allows us to create custom methods by using this route:
config.Routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
This Web API route takes an action in the URI via the {action} placeholder. The action placeholder is a string that will match the method name that is specified in the Web API controller. This is possible because we are not allowing strings in the “DefaultApiWithId” route that we mentioned previously.
A problem that was encountered on the Youngevity project was that the Ids that were used from a third party api included numbers and letters. So if an id with both integers and letters was passed in the URI like:
api/customers/RA1234
then the route would match the DefaultApiWithAction route and would attempt to find a Web API controller method called RA1234. This problem will most likely be encountered again in the future on projects.
So what are the possible options for routing to allow a string as an id?
1) Pass the id in the querystring to bypass routing alltogether and let the controller parse the id out of the querystring
2) Reconfigure the routing that we already have in place and specify a route that accepts an id as a string
3) Create a custom GET method that takes in a string as an id parameter
The method we have chosen to use is the third. When I first looked at the problem I thought “I don’t want to create a custom method to do a normal GET method” but after thinking about the problem and talking to Ty realized that Ids should be created as integers or guids and that a string as an Id is actually an abnormal situation that should be handled via a custom method.
The simple solution:
1) Create a custom method like GetCustomerByString and decorate with the HttpGet attribute
2) Call the method via a URI like: api/customers/GetCustomerByString/RA1234