Resolve ${var} values in middleware.json

App variables can now be specified in middleware.json using the ${var}
format. The value of var is looked up using app.get().

This allows loopback.rest and other loopback middleware which require
app variables, to be loaded declaratively using middleware.json.
This commit is contained in:
Hack Sparrow 2015-08-13 15:32:31 +05:30 committed by Hage Yaapa
parent 674a8da693
commit 8b475a97b2
3 changed files with 134 additions and 1 deletions

View File

@ -316,10 +316,50 @@ function setupMiddleware(app, instructions) {
}
assert(typeof factory === 'function',
'Middleware factory must be a function');
data.config = getUpdatedConfigObject(data.config, app);
app.middlewareFromConfig(factory, data.config);
});
}
function getUpdatedConfigObject(config, app) {
var DYNAMIC_CONFIG_PARAM = /\$\{(\w+)\}$/;
function getConfigVariable(param) {
var configVariable = param;
var match = configVariable.match(DYNAMIC_CONFIG_PARAM);
if (match) {
var appValue = app.get(match[1]);
if (appValue !== undefined) {
configVariable = appValue;
} else {
console.warn('%s does not resolve to a valid value. ' +
'"%s" must be resolvable by app.get().', param, match[1]);
}
}
return configVariable;
}
function interpolateVariables(config) {
var interpolated = {};
Object.keys(config).forEach(function(configKey) {
var value = config[configKey];
if (Array.isArray(value)) {
interpolated[configKey] = value.map(getConfigVariable);
} else if (typeof value === 'string') {
interpolated[configKey] = getConfigVariable(value);
} else if (typeof value === 'object' && Object.keys(value).length) {
interpolated[configKey] = interpolateVariables(value);
} else {
interpolated[configKey] = value;
}
});
return interpolated;
}
return interpolateVariables(config);
}
function setupComponents(app, instructions) {
instructions.components.forEach(function(data) {
debug('Configuring component %j', data.sourceFile);

View File

@ -292,7 +292,7 @@ describe('executor', function() {
});
});
describe ('for mixins', function() {
describe('for mixins', function() {
var options;
beforeEach(function() {
appdir.writeFileSync('custom-mixins/example.js',
@ -425,6 +425,77 @@ describe('executor', function() {
});
});
describe('with middleware.json', function() {
it('should parse a simple config variable', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{ path: '${restApiRoot}' }
));
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.path).to.equal(app.get('restApiRoot'));
done();
});
});
it('should parse multiple config variables', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{ path: '${restApiRoot}', env: '${env}' }
));
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.path).to.equal(app.get('restApiRoot'));
expect(res.body.env).to.equal(app.get('env'));
done();
});
});
it('should parse config variables in an array', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{ paths: ['${restApiRoot}'] }
));
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.paths).to.eql(
[app.get('restApiRoot')]
);
done();
});
});
it('should parse config variables in an object', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{ info: { path: '${restApiRoot}' } }
));
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.info).to.eql({
path: app.get('restApiRoot')
});
done();
});
});
it('should parse config variables in a nested object', function(done) {
boot.execute(app, simpleMiddlewareConfig('routes',
{ nested: { info: { path: '${restApiRoot}' } } }
));
supertest(app).get('/').end(function(err, res) {
if (err) return done(err);
expect(res.body.nested).to.eql({
info: { path: app.get('restApiRoot') }
});
done();
});
});
});
it('calls function exported by boot/init.js', function() {
var file = appdir.writeFileSync('boot/init.js',
'module.exports = function(app) { app.fnCalled = true; };');
@ -583,6 +654,23 @@ describe('executor', function() {
});
});
function simpleMiddlewareConfig(phase, params) {
return someInstructions({
middleware: {
phases: [phase],
middleware: [
{
sourceFile: path.join(__dirname, './fixtures/simple-middleware.js'),
config: {
phase: phase,
params: params
}
}
]
}
});
}
function assertValidDataSource(dataSource) {
// has methods
assert.isFunc(dataSource, 'createModel');

5
test/fixtures/simple-middleware.js vendored Normal file
View File

@ -0,0 +1,5 @@
module.exports = function(params) {
return function(req, res, next) {
res.send(params);
};
};