I'm making classic stateless RESTfull APIs on Symfony2: users/apps gets an authentication token on the authenticate API and give it to all others APIs to be logged and post data / access protected/private/personal data on others APIs.
I've got now three concerns regarding this workflow and caching:
How to use HTTP cache for my 'static' APIs (that always deliver the same content, regardless the logged user and its token) assuming that different tokens would be passed in the url by different users for the same API, so that the url would never be the same? How to use HTTP shared cache then?
I've got APIs for the same url that produce a different output, regarding the logged user rights (I've basically 4 different rights levels). Question is: is it a good pattern? It is not better to have 4 different urls, one for each right, that I could cache? If not, how to implement a proper cache on that?
Is shared HTTP Cache working on HTTPS? If not, which type of caching should I implement, and how?
Thanks for your answers and lights on that.
I have had a similar issue (with all 3 scenarios) and have used the following strategy successfully with Symfony's built-in reverse-proxy cache:
If using Apache, update .htaccess
to add an environment variable for your application to the http cache off of (NOTE: environment automatically adds REDIRECT_
to the environment variable):
# Add `REDIRECT_CACHE` if API subdomain
RewriteCond %{HTTP_HOST} ^api\.
RewriteRule .* - [E=CACHE:1]
# Add `REDIRECT_CACHE` if API subfolder
RewriteRule ^api(.*)$ - [E=CACHE:1]
Add this to app.php
after instantiating AppKernel
:
// If environment instructs us to use cache, enable it
if (getenv('CACHE') || getenv('REDIRECT_CACHE')) {
require_once __DIR__.'/../app/AppCache.php';
$kernel = new AppCache($kernel);
}
For your "static" APIs, all you have to do is take your response object and modify it:
$response->setPublic();
$response->setSharedMaxAge(6 * 60 * 60);
Because you have a session, user or security token, Symfony effectively defaults to $response->setPrivate()
.
Regarding your second point, REST conventions (as well as reverse-proxy recommendations), GET & HEAD requests aren't meant to change between requests. Because of this, if content changes based on the logged in user, you should set the response to private & prevent caching at all for the reverse-proxy cache.
If caching is required for speed, it should be handled internally & not by the reverse-proxy.
Because we didn't want to introduce URLs based on each user role, we simply cached the response by role internally (using Redis) & returned it directly rather than letting the cache (mis)handle it.
As for your third point, because HTTP & HTTPS traffic are hitting the same cache & the responses are having public/private & cache-control settings explicitly set, the AppCache
is serving the same response both secure & insecure traffic.
I hope this helps as much as it has for me!