Tag Archive for: WebAPI

Testing POST methods for REST services

Applying security to WebAPI controllers

When using the Reurgency.Common framework, every REST service method requires security permissions to be applied via an attribute on either the method or the class.  This blog post describes how to do that.

First add some USING statements.

using Reurgency.Foundation.WebApi;
using Reurgency.Foundation.WebApi.Filters;

Then add the attribute HandleSecurityTokenRequest to either the class or individual methods

Here is an example of using the attribute on a class. ALL methods in the class will inherit this setting.

[HandleSecurityTokenRequest(AllowAnonymous = false)]
public class EmployeesController : <Employee>
{

That’s it.  You are done.

Read on to understand a little more how this works.

Here is an example of a using the attribute on a method. This is useful when you want to set different security on each method within a class.

[HandleSecurityTokenRequest(AllowAnonymous = true)]
[HttpPost]
public HttpResponseMessage Login(Credential credential)
{
BusinessCommandRepository biz = new BusinessCommandRepository(this.securityTokenId, "Login");

As you can see the attribute takes in one parameter called AllowAnonymous.  When set to false the system expects that a valid security token is passed in via headers or cookies.  If a valid security token is not passed in an HTTP Status code of 401 is returned to the client.   When AllowAnonymous is set to true, then the system will first look for a valid security token in the header or cookies and use that, else it will use the constant defined in Reurgency.Common.Model.Entities.SecurityToken.ANONYMOUSSECURITYTOKEN.

Each WebAPI method is responsible for instantiating the BusinessCommandRepository.  The constructor for that class requires a security token.  Simply use this.securityTokenId.

BusinessCommandRepository biz = new BusinessCommandRepository(this.securityTokenId, "Login");

The securityTokenId property is part of Reurgency.Foundation.WebApi.WebApiController.  Every one of your WebAPI controllers should inherit from this class.

It is the responsibility of the HandleSecurityTokenRequest filter attribute to populate this.securityTokenId from either header, cookies, or ANONYMOUSSECURITYTOKEN.  Because the filters are processed PRIOR to the WebAPI method’s execution, you are guaranteed that this.securityTokenId will be populated or a 401 error will be thrown.

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