-
-
Save jgeewax/3b351d3522fdf061bdea to your computer and use it in GitHub Desktop.
var express = require('express'); | |
var app = express(); | |
var gcloud = require('gcloud')({ /* extra config here */ }); | |
var dataset = gcloud.datastore.dataset({ /* projectId: my-project */ }); | |
// Set the trace ID on a per-request basis via middleware | |
// (See http://expressjs.com/guide/writing-middleware.html) | |
app.use(function(req, res, next) { | |
// Need to double check that this works from a thread safety perspective. | |
gcloud.setTraceContext(req.headers['X-Cloud-Trace-Context']); | |
}); | |
// Get companies from the datastore. | |
app.get('/company/:id', function(req, res, next) { | |
var key = dataset.Key(['Company', req.params.id]); | |
// This request will have the trace ID that was set by the middleware. | |
// So whatever was in the request header will be automatically forwarded along. | |
dataset.get(key).on('data', function(entity) { | |
res.send(entity); | |
}); | |
}); |
Can you configure a dataset/gcloud more than once? Effectively "forking" it? If so...
var express = require('express');
var app = express();
var gcloud = require('gcloud')({ /* extra config here */ });
var dataset = gcloud.datastore.dataset({projectId: 'my-project'});
// Set the trace ID on a per-request basis via middleware
// (See http://expressjs.com/guide/writing-middleware.html)
app.use(function(req, res, next) {
res.locals.dataset = dataset({
decorateRequest: function(reqOpts) {
reqOpts.headers['X-Cloud-Trace-Context'] = req.headers['X-Cloud-Trace-Context'];
return reqOpts;
}
});
next();
});
// Get companies from the datastore.
app.get('/company/:id', function(req, res, next) {
var dataset = res.locals.dataset;
var key = dataset.Key(['Company', req.params.id]);
// This request will have the trace ID that was set by the middleware.
// So whatever was in the request header will be automatically forwarded along.
dataset.get(key).on('data', function(entity) {
res.send(entity);
});
});
And this opens the question (@stephenplusplus), can we change the parent only and have the decorator inherit down somehow...? ie...
var gcloud = require('gcloud')(...);
var dataset = gcloud.datastore.dataset(...);
var decorator = function() {};
gcloud.magicallySetDecorator(decorator);
assert.equals(dataset.getDecorator(), decorator);
Each invocation of dataset()
returns a fresh auth client. So having to create one on each GET means you'd also end up doing a fresh token grab every time. But without scoping request option manipulation to the object, you'd inevitably run into concurrency issues, so it might be a fair trade off for what is not the 99% use case?
If not, we can go the forking route, but it'd have to be from a new method (like dataset.clone()
) that would reuse/override options.
var dataset = gcloud.datastore.dataset({ projectId: 'my-project' });
app.use(function(req, res, next) {
res.locals.dataset = dataset.clone({
decorateRequest: function(reqOpts) {
reqOpts.headers['X-Cloud-Trace-Context'] = req.headers['X-Cloud-Trace-Context'];
return reqOpts;
}
});
next();
});
And an option that is less "it's as easy as 1-2-3" for the user, but possibly easier to grasp / re-usable and expandable down the road:
var opts = { projectId: 'my-project-id' };
var dataset = gcloud.datastore.dataset(opts);
app.use(function(req, res, next) {
res.locals.dataset = gcloud.datastore.dataset(extend(opts, {
authClient: dataset.authClient, // expose and re-use the authClient
decorateRequest: function(reqOpts) {
reqOpts.headers['X-Cloud-Trace-Context'] = req.headers['X-Cloud-Trace-Context'];
}
}));
next();
});
There are many ways to implement the above concept with/without using extend
, using helper functions, etc, so if it doesn't suit your taste in terms of style, try to look past :)
And this opens the question (@stephenplusplus), can we change the parent only and have the decorator inherit down somehow...? ie...
Man, gists really need email notifications or something. I'm always one step behind.
But yeah, I would expect the user to expect an inheritance model, where anything set on the highest level cascades downwards, and the lowest object wins in the event of a conflict:
var gcloud = require('gcloud')({
decorateRequest: function(reqOpts) {
reqOpts.headers['A'] = 1;
reqOpts.headers['B'] = 1;
return reqOpts;
}
});
var bucket = gcloud.bucket({
decorateRequest: function(reqOpts) {
reqOpts.headers['A'] = 2;
return reqOpts;
}
});
bucket.getMetadata();
// GET https://...
// A: 2
// B: 1
Sure, but the example we're talking about is...
var gcloud = require('gcloud');
var bucket = gcloud.bucket();
var threadLocalgcloud = gcloud({
decorateRequest: function(reqOpts) {
reqOpts.headers['A'] = 1;
return reqOpts;
}
});
bucket.getMetadata();
// GET https://...
// A: 1
That is, I mess with the parent somehow, and the pre-created child gets updated... It seems like that wouldn't be possible to me.... right?
In that example, bucket.getMetadata()
would not know anything about the decorated request options. You would have to access the bucket from threadLocalgcloud.bucket()
to have that stuff on there.
In a practical use, if I need to decorate all requests, I would do this:
var gcloud = require('gcloud')({
decorateRequest: function(reqOpts) {
reqOpts.headers['A'] = 1;
reqOpts.headers['B'] = 1;
return reqOpts;
}
});
Proposal: