ETags in Laravel 4 using Filters

Laravel 4 has some very nice features in which you can build your api on. After reading about some best practices for REST many people suggest using ETags for validation caching. I’ve come up with a realtivley simple solution to enable ETag validation of your api data.

I simply used a filter to catch the response after it was created, created an md5 hash of the content and compared it with ETag in the request. The code in my app/routes.php looks something like this:

Route::filter('etag', function($route, $request, $response){
  $etag = md5($response->getContent());
  $requestETag = str_replace('"', '', $request->getETags());

  if($requestETag && $requestETag[0] == $etag){
    $response->setNotModified();
  }

  $response->setEtag($etag);
	
  return;
});

Route::group(array(
    'prefix'	=> 'api/v1',
    'after'	=> 'etag'
  ),
  function()
  {
    Route::resource('invoice', 'V1\InvoicesController');
  }
);

Now when I fetch an invoice an Etag is generated, and compared with the one supplied in the request. If they match, the body is discarded and a 304 is sent back.

This obviously has a few gotchas:

  • It will not lower any server load. In fact this might slightly increase load since you’ll be generating and comapring ETags on each request. This is simply a bandwidth saving solution for you and the client.
  • I’m hashing the entire body content. For some this might be undesirable. As a minimum hash the data that you need to know if it changed since the last request.
  • This doesn’t replace other caching methods like memcached, it’s meant to work along side it.

References:
http://fideloper.com/laravel4-etag-conditional-get

  • Maxime Fabre

    Posting on an old thread here but this can be simplied drastically using Symfony methods :

    “`
    Route::filter(‘etags’, function($route, $request, $response) {
    $response->setEtag(md5($response->getContent()));
    $response->isNotModified($request);
    });

    “`

  • http://www.makesomecode.com/ Nick Verwymeren

    Thanks Maxime, I wasn’t aware of the Symfony methods.