Unifying REST Methods with iRules

REST (Representational State Transfer) is a web architecture that allows a CRUD (Create, read, update, delete) model to be implemented via HTTP. The ideal REST architecture makes use of the HTTP methods described in RFC 2616 and simple URIs to correlate an action with a specific resource.

If we wanted to create a resource in a web-based CRM (Customer Relationship Management) system using a REST interface, we might send a request that looks something like this:

PUT /CRM/Customer HTTP 1.1
Host: www.example.com
Connection: Keep-Alive

[ the new customer record data in a format recognizable by the CRM system ]

Similarly, if you wanted to remove a customer record you would use the DELETE method, the GET method for retrieving a resource, etc… By using the HTTP method, the URI, and the data exchanged, a REST-based system allows for the creation of a very services-oriented architecture without the overhead of its accepted SOA counterparts, namely SOAP (Simple Object Access Protocol) and XML.

There are two problems with implementing a REST-based system. First, many browsers do not support all – or even most of – the HTTP methods. While all browsers support GET and POST (though some do not fully implement POST correctly) almost no browser supports the DELETE and PUT methods.

The second issue with implementing a REST-based architecture is that some of the HTTP methods required, notably PUT and DELETE, are generally disabled on web servers as a security measure. It may not be possible for developers or architects to argue against a security policy that disallows these HTTP methods because they do, unfortunately, open potential vectors of attack through which malicious code and other attacks might be launched.

This all makes it very difficult to implement a REST-based system.

The concept of REST bridging has been put into practice at service providers whom have chosen to provide a REST API to enable data sharing (integration) and third-party application development for their services. These providers recognize the simplicity and power of a REST-based solution and have come up with a solution that works around the inherent browser limitations on some of the necessary HTTP methods. The OpenSocial and Gadgets Specification Group has a great discussion on the concept of REST bridging that may be of interest.

Bridging the Gap

There are essentially two methods described for implementing REST bridging. The first is to use a URL query parameter to specific the desired method, much as I described in a previous discussion on REST and its limitations.  

The second is to use a custom HTTP header to “override” the HTTP method actually used to send the request. For example, the actual request might be sent using GET, but the custom HTTP header “X-HTTPMethodOverride” indicates a PUT, instead.

Let’s look at the creation of a customer record again, this time using the two different REST methods.

URL Query method:

GET /CRM/Customer?method=PUT  HTTP 1.1
Host: www.example.com
Connection: Keep-Alive

[ the new customer record data in a format recognizable by the CRM system ]

Custom HTTP header method:

GET /CRM/Customer HTTP 1.1
Host: www.example.com
Connection: Keep-Alive
X-HTTPMethodOverride  PUT

[ the new customer record data in a format recognizable by the CRM system ]

The problem with this type of implementation, of course, is that your application needs to support both methods, and that makes the application code more complex and provides two avenues for exploitation instead of one that must be actively protected.

The optimal solution to this dilemma is to allow the developers to use either method, but support only one method on the server. That’s where iRules comes in.

Unified REST Access

No matter which method you choose to implement within your application, iRules can accommodate and provide both methods of access to external developers.

Let’s assume that you’ve chosen to use the custom HTTP header method for your application. What you need is an iRule that extracts the method from the URL query and inserts the custom HTTP header before sending it on to your application.

 

when HTTP_REQUEST {

  set namevals [split [HTTP::query] "&"]

  for {set i 0} {$i < [llength $namevals]} {incr i} {

    set params [split [lindex $namevals $i] "="]

    if { [string tolower [lindex $params 0]] eq "method" } {

       set xmethod [string toupper [lindex $params 1]]

       HTTP::header insert "X-HTTPMethodOverride $xmethod"

    }

  }

}

 

Conversely, if you want your application to base its actions on URL query parameters and the developer sends in a custom HTTP header, we need to extract the header and append it to the URL query parameters.

 

when HTTP_REQUEST {

   if {  [HTTP::header exists "X-HTTPMethodOverride"] } {

      set xmethod [HTTP::header "X-HTTPMethodOverride"]

      if { [string length [HTTP::query]] == 0 } {

         set delim "?"

      } else {

         set delim "&"

      }

      set newstr “[HTTP::uri]$delim”

      append newstr “method=$xmethod”

      HTTP::uri $newstr

   }

}

 

Conclusion

 

That's all you need to unify REST access without making changes to your application, or requiring third-party developers to modify the way in which they call your APIs. Using a BIG-IP and iRules you can transparently transform requests using multiple mechanisms to simplify and make more secure your REST based API.