Tag protocol
============

Build proxy cache keys using tags set by application, and let application
invalidate all url for a given tag at once.

Usage
-----

```js
var tag = require('tag');

// setup a global app tag,

app.use(tag('app'));

app.post('/protected/purge', tag('app'), function(req, res, next) {
 // see "scope" for setting up permissions
 res.sendStatus(200);
});

// per-resource tagging

app.get('/api/collection', tag('zone'), appMw);
app.post('/api/collection', tag('zone'), appMw);

// multiple tags can be set
app.get('/api/other', tag('zone', 'all'), ...);

// a route can invalidate tags set on other routes
app.put('/api/sample', tag('all'), ...);

// a tag can depend on the route using req.locals or req.params replacement
// no replacement is made if no param is defined.
app.get('/:domain/list', tag(':domain'), ...);


app.use(function(req, res, next) {
  res.locals.test = "test";
  next();
}, tag('has-:test'));

// if the replaced parameter is null, the tag is not added

```

`tag(...)(req, res, next)` can also be called directly, next being optional.

The last argument of tag() can be a function replacing the default deciding
when tags must be incremented:

```js
function incFn(req) {
 return req.method != "GET";
}
```

Simplified access to cache-control directives is made available through
`tag.for(...)` or `tag(...).for(...)` method,
which accepts one argument:

- string or number: a ttl in string format or in seconds
- object: options for [express-cache-response-directive](https://github.com/kapouer/express-cache-response-directive).

A `for()` call has no effect if the previous `tag()` call actually did not insert a tag.

A middleware for disabling cache is also available with `tag.disable()`.
If set, other calls to `tag.for()` on the same route will be ignored.

```js
app.get('/api/stats', tag.for('1d'), appMw);
app.get('/api/user', tag('user-*').for('10min'), appMw);
app.get('/api/user', tag('user-*').for(3600), appMw);

app.get('/trigger', tag.disable(), ...); // disable cache
```

Cache protocol
--------------

Application tags resources by replying `X-Upcache-Tag: mytag` response header
to set resource to latest known value for that tag, or `X-Upcache-Tag: +mytag`
to increment the value known by the proxy for that tag.

Proxy stores `mytag` as a sub-variant tag key for that url, and stores that
value (or zero if initial) for that tag.
This is like a `Vary: mytag` where `mytag` actual value is stored internally.

The cache key formula is `mytag=curval`. Thus all tagged resources can be
invalidated at once without any performance impact: the variants cache and the
cache storage backend are both LRU caches, so they don't actually need to be
purged - requests keys just need to be changed.

For now only the proxy knows the tags values.

Golden rule
-----------

Never set a max-age on a mutable resource (unless you know it's okay to serve it perempted),
only set a tag.

Sample setup
------------

```js
// application-level tag, changes when application version changes
app.get('*', tag('app'));
// static files tag, changes upon application restart
app.get('*.*', tag('static'), express.static(...));
// dynamic tag, changes upon non-GET calls
app.use('/api/*', tag('dynamic'));
```

and invalidation of that tag can take place upon application restart:

```js
app.post('/.upcache', function(req, res, next) {
  if (config.version != config.previousVersion) {
    console.info(`app tag changes because version changes from ${config.previousVersion} to ${config.version}`);
    config.previousVersion = config.version;
    tag('app')(req, res, next);
  } else {
    next();
  }
}, function(req, res, next) {
  if (!config.invalidated) {
    console.info(`static tag changes after restart`);
    config.invalidated = true;
    tag('static')(req, res, next);
  } else {
    next();
  }
}, function(req, res) {
  res.sendStatus(204);
});
```
