Load middleware and phases from `middleware.json`
Sample JSON: { "routes:before": { "morgan": { "params": ["dev"] } }, "routes": { "loopback/server/middleware/rest": { } }, "subapps": { "./adminer": { }, } } The JSON file can be customized using the usual conventions: - middleware.local.{js|json} - middleware.{env}.{js|json} It is also possible to mount the same middleware in the same phase multiple times with different configuration. Example config: { "auth": { "oauth2": [ { "params": "first" }, { "params": "second" } ] }, });
This commit is contained in:
parent
08fcc5faa7
commit
1114bc9227
2
index.js
2
index.js
|
@ -107,6 +107,8 @@ var addInstructionsToBrowserify = require('./lib/bundler');
|
||||||
* `production`; however the applications are free to use any names.
|
* `production`; however the applications are free to use any names.
|
||||||
* @property {Array.<String>} [modelSources] List of directories where to look
|
* @property {Array.<String>} [modelSources] List of directories where to look
|
||||||
* for files containing model definitions.
|
* for files containing model definitions.
|
||||||
|
* @property {Object} [middleware] Middleware configuration to use instead
|
||||||
|
* of `{appRootDir}/middleware.json`
|
||||||
* @property {Array.<String>} [bootDirs] List of directories where to look
|
* @property {Array.<String>} [bootDirs] List of directories where to look
|
||||||
* for boot scripts.
|
* for boot scripts.
|
||||||
* @property {Array.<String>} [bootScripts] List of script files to execute
|
* @property {Array.<String>} [bootScripts] List of script files to execute
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var commondir = require('commondir');
|
var commondir = require('commondir');
|
||||||
|
var cloneDeep = require('lodash.clonedeep');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add boot instructions to a browserify bundler.
|
* Add boot instructions to a browserify bundler.
|
||||||
|
@ -60,6 +61,17 @@ function addScriptsToBundle(name, list, bundler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function bundleInstructions(instructions, bundler) {
|
function bundleInstructions(instructions, bundler) {
|
||||||
|
instructions = cloneDeep(instructions);
|
||||||
|
|
||||||
|
var hasMiddleware = instructions.middleware.phases.length ||
|
||||||
|
instructions.middleware.middleware.length;
|
||||||
|
if (hasMiddleware) {
|
||||||
|
console.warn(
|
||||||
|
'Discarding middleware instructions,' +
|
||||||
|
' loopback client does not support middleware.');
|
||||||
|
}
|
||||||
|
delete instructions.middleware;
|
||||||
|
|
||||||
var instructionsString = JSON.stringify(instructions, null, 2);
|
var instructionsString = JSON.stringify(instructions, null, 2);
|
||||||
|
|
||||||
/* The following code does not work due to a bug in browserify
|
/* The following code does not work due to a bug in browserify
|
||||||
|
|
|
@ -44,6 +44,14 @@ module.exports = function compile(options) {
|
||||||
ConfigLoader.loadDataSources(dsRootDir, env);
|
ConfigLoader.loadDataSources(dsRootDir, env);
|
||||||
assertIsValidConfig('data source', dataSourcesConfig);
|
assertIsValidConfig('data source', dataSourcesConfig);
|
||||||
|
|
||||||
|
// not configurable yet
|
||||||
|
var middlewareRootDir = appRootDir;
|
||||||
|
|
||||||
|
var middlewareConfig = options.middleware ||
|
||||||
|
ConfigLoader.loadMiddleware(middlewareRootDir, env);
|
||||||
|
var middlewareInstructions =
|
||||||
|
buildMiddlewareInstructions(middlewareRootDir, middlewareConfig);
|
||||||
|
|
||||||
// require directories
|
// require directories
|
||||||
var bootDirs = options.bootDirs || []; // precedence
|
var bootDirs = options.bootDirs || []; // precedence
|
||||||
bootDirs = bootDirs.concat(path.join(appRootDir, 'boot'));
|
bootDirs = bootDirs.concat(path.join(appRootDir, 'boot'));
|
||||||
|
@ -67,6 +75,7 @@ module.exports = function compile(options) {
|
||||||
config: appConfig,
|
config: appConfig,
|
||||||
dataSources: dataSourcesConfig,
|
dataSources: dataSourcesConfig,
|
||||||
models: modelInstructions,
|
models: modelInstructions,
|
||||||
|
middleware: middlewareInstructions,
|
||||||
files: {
|
files: {
|
||||||
boot: bootScripts
|
boot: bootScripts
|
||||||
}
|
}
|
||||||
|
@ -338,3 +347,46 @@ function loadModelDefinition(rootDir, jsonFile, allFiles) {
|
||||||
sourceFile: sourceFile
|
sourceFile: sourceFile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildMiddlewareInstructions(rootDir, config) {
|
||||||
|
var phasesNames = Object.keys(config);
|
||||||
|
var middlewareList = [];
|
||||||
|
phasesNames.forEach(function(phase) {
|
||||||
|
var phaseConfig = config[phase];
|
||||||
|
Object.keys(phaseConfig).forEach(function(middleware) {
|
||||||
|
var start = middleware.substring(0, 2);
|
||||||
|
var sourceFile = start !== './' && start !== '..' ?
|
||||||
|
middleware :
|
||||||
|
path.resolve(rootDir, middleware);
|
||||||
|
|
||||||
|
var allConfigs = phaseConfig[middleware];
|
||||||
|
if (!Array.isArray(allConfigs))
|
||||||
|
allConfigs = [allConfigs];
|
||||||
|
|
||||||
|
allConfigs.forEach(function(config) {
|
||||||
|
var middlewareConfig = cloneDeep(config);
|
||||||
|
middlewareConfig.phase = phase;
|
||||||
|
|
||||||
|
middlewareList.push({
|
||||||
|
sourceFile: require.resolve(sourceFile),
|
||||||
|
config: middlewareConfig
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var flattenedPhaseNames = phasesNames
|
||||||
|
.map(function getBaseName(name) {
|
||||||
|
return name.replace(/:[^:]+$/, '');
|
||||||
|
})
|
||||||
|
.filter(function differsFromPreviousItem(value, ix, source) {
|
||||||
|
// Skip duplicate entries. That happens when
|
||||||
|
// `name:before` and `name:after` are both translated to `name`
|
||||||
|
return ix === 0 || value !== source[ix - 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
phases: flattenedPhaseNames,
|
||||||
|
middleware: middlewareList
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,16 @@ ConfigLoader.loadModels = function(rootDir, env) {
|
||||||
return tryReadJsonConfig(rootDir, 'model-config') || {};
|
return tryReadJsonConfig(rootDir, 'model-config') || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load middleware config from `middleware.json` and friends.
|
||||||
|
* @param {String} rootDir Directory where to look for files.
|
||||||
|
* @param {String} env Environment, usually `process.env.NODE_ENV`
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
ConfigLoader.loadMiddleware = function(rootDir, env) {
|
||||||
|
return loadNamed(rootDir, env, 'middleware', mergeMiddlewareConfig);
|
||||||
|
};
|
||||||
|
|
||||||
/*-- Implementation --*/
|
/*-- Implementation --*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,6 +136,32 @@ function mergeAppConfig(target, config, fileName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mergeMiddlewareConfig(target, config, fileName) {
|
||||||
|
var err;
|
||||||
|
for (var phase in config) {
|
||||||
|
if (phase in target) {
|
||||||
|
err = mergePhaseConfig(target[phase], config[phase], phase);
|
||||||
|
} else {
|
||||||
|
err = 'The phase "' + phase + '" is not defined in the main config.';
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
throw new Error('Cannot apply ' + fileName + ': ' + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergePhaseConfig(target, config, phase) {
|
||||||
|
var err;
|
||||||
|
for (var middleware in config) {
|
||||||
|
if (middleware in target) {
|
||||||
|
err = mergeObjects(target[middleware], config[middleware]);
|
||||||
|
} else {
|
||||||
|
err = 'The middleware "' + middleware + '" in phase "' + phase + '"' +
|
||||||
|
'is not defined in the main config.';
|
||||||
|
}
|
||||||
|
if (err) return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function mergeObjects(target, config, keyPrefix) {
|
function mergeObjects(target, config, keyPrefix) {
|
||||||
for (var key in config) {
|
for (var key in config) {
|
||||||
var fullKey = keyPrefix ? keyPrefix + '.' + key : key;
|
var fullKey = keyPrefix ? keyPrefix + '.' + key : key;
|
||||||
|
|
|
@ -26,6 +26,7 @@ module.exports = function execute(app, instructions, callback) {
|
||||||
|
|
||||||
setupDataSources(app, instructions);
|
setupDataSources(app, instructions);
|
||||||
setupModels(app, instructions);
|
setupModels(app, instructions);
|
||||||
|
setupMiddleware(app, instructions);
|
||||||
|
|
||||||
// Run the boot scripts in series synchronously or asynchronously
|
// Run the boot scripts in series synchronously or asynchronously
|
||||||
// Please note async supports both styles
|
// Please note async supports both styles
|
||||||
|
@ -250,6 +251,30 @@ function tryRequire(modulePath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupMiddleware(app, instructions) {
|
||||||
|
if (!instructions.middleware) {
|
||||||
|
// the browserified client does not support middleware
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var phases = instructions.middleware.phases;
|
||||||
|
assert(Array.isArray(phases),
|
||||||
|
'instructions.middleware.phases must be an array');
|
||||||
|
|
||||||
|
var middleware = instructions.middleware.middleware;
|
||||||
|
assert(Array.isArray(middleware),
|
||||||
|
'instructions.middleware.middleware must be an object');
|
||||||
|
|
||||||
|
debug('Defining middleware phases %j', phases);
|
||||||
|
app.defineMiddlewarePhases(phases);
|
||||||
|
|
||||||
|
middleware.forEach(function(data) {
|
||||||
|
debug('Configuring middleware %j', data.sourceFile);
|
||||||
|
var factory = require(data.sourceFile);
|
||||||
|
app.middlewareFromConfig(factory, data.config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function runBootScripts(app, instructions, callback) {
|
function runBootScripts(app, instructions, callback) {
|
||||||
runScripts(app, instructions.files.boot, callback);
|
runScripts(app, instructions.files.boot, callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -673,6 +673,186 @@ describe('compiler', function() {
|
||||||
expect(instructions.config).to.not.have.property('modified');
|
expect(instructions.config).to.not.have.property('modified');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('for middleware', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
appdir.createConfigFilesSync();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits middleware instructions', function() {
|
||||||
|
appdir.writeConfigFileSync('middleware.json', {
|
||||||
|
initial: {
|
||||||
|
},
|
||||||
|
custom: {
|
||||||
|
'loopback/server/middleware/url-not-found': {
|
||||||
|
params: 'some-config-data'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware).to.eql({
|
||||||
|
phases: ['initial', 'custom'],
|
||||||
|
middleware: [{
|
||||||
|
sourceFile:
|
||||||
|
require.resolve('loopback/server/middleware/url-not-found'),
|
||||||
|
config: {
|
||||||
|
phase: 'custom',
|
||||||
|
params: 'some-config-data'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails when a module middleware cannot be resolved', function() {
|
||||||
|
appdir.writeConfigFileSync('middleware.json', {
|
||||||
|
final: {
|
||||||
|
'loopback/path-does-not-exist': { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(function() { boot.compile(appdir.PATH); })
|
||||||
|
.to.throw(/path-does-not-exist/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves paths relatively to appRootDir', function() {
|
||||||
|
appdir.writeConfigFileSync('./middleware.json', {
|
||||||
|
routes: {
|
||||||
|
// resolves to ./middleware.json
|
||||||
|
'./middleware': { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware).to.eql({
|
||||||
|
phases: ['routes'],
|
||||||
|
middleware: [{
|
||||||
|
sourceFile: path.resolve(appdir.PATH, 'middleware.json'),
|
||||||
|
config: { phase: 'routes' }
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges config.params', function() {
|
||||||
|
appdir.writeConfigFileSync('./middleware.json', {
|
||||||
|
routes: {
|
||||||
|
'./middleware': {
|
||||||
|
params: {
|
||||||
|
key: 'initial value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appdir.writeConfigFileSync('./middleware.local.json', {
|
||||||
|
routes: {
|
||||||
|
'./middleware': {
|
||||||
|
params: {
|
||||||
|
key: 'custom value',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware.middleware[0].config.params).to.eql({
|
||||||
|
key: 'custom value'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges config.enabled', function() {
|
||||||
|
appdir.writeConfigFileSync('./middleware.json', {
|
||||||
|
routes: {
|
||||||
|
'./middleware': {
|
||||||
|
params: {
|
||||||
|
key: 'initial value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
appdir.writeConfigFileSync('./middleware.local.json', {
|
||||||
|
routes: {
|
||||||
|
'./middleware': {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware.middleware[0].config)
|
||||||
|
.to.have.property('enabled', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('flattens sub-phases', function() {
|
||||||
|
appdir.writeConfigFileSync('middleware.json', {
|
||||||
|
'initial:after': {
|
||||||
|
},
|
||||||
|
'custom:before': {
|
||||||
|
'loopback/server/middleware/url-not-found': {
|
||||||
|
params: 'some-config-data'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'custom:after': {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware.phases, 'phases')
|
||||||
|
.to.eql(['initial', 'custom']);
|
||||||
|
expect(instructions.middleware.middleware, 'middleware')
|
||||||
|
.to.eql([{
|
||||||
|
sourceFile:
|
||||||
|
require.resolve('loopback/server/middleware/url-not-found'),
|
||||||
|
config: {
|
||||||
|
phase: 'custom:before',
|
||||||
|
params: 'some-config-data'
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports multiple instances of the same middleware', function() {
|
||||||
|
|
||||||
|
appdir.writeConfigFileSync('middleware.json', {
|
||||||
|
'final': {
|
||||||
|
'./middleware': [
|
||||||
|
{
|
||||||
|
params: 'first'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: 'second'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var instructions = boot.compile(appdir.PATH);
|
||||||
|
|
||||||
|
expect(instructions.middleware.middleware)
|
||||||
|
.to.eql([
|
||||||
|
{
|
||||||
|
sourceFile: path.resolve(appdir.PATH, 'middleware.json'),
|
||||||
|
config: {
|
||||||
|
phase: 'final',
|
||||||
|
params: 'first'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceFile: path.resolve(appdir.PATH, 'middleware.json'),
|
||||||
|
config: {
|
||||||
|
phase: 'final',
|
||||||
|
params: 'second'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function getNameProperty(obj) {
|
function getNameProperty(obj) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ var expect = require('chai').expect;
|
||||||
var fs = require('fs-extra');
|
var fs = require('fs-extra');
|
||||||
var sandbox = require('./helpers/sandbox');
|
var sandbox = require('./helpers/sandbox');
|
||||||
var appdir = require('./helpers/appdir');
|
var appdir = require('./helpers/appdir');
|
||||||
|
var supertest = require('supertest');
|
||||||
|
|
||||||
var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-app');
|
var SIMPLE_APP = path.join(__dirname, 'fixtures', 'simple-app');
|
||||||
|
|
||||||
|
@ -18,6 +19,13 @@ describe('executor', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
app = loopback();
|
app = loopback();
|
||||||
|
|
||||||
|
// process.bootFlags is used by simple-app/boot/*.js scripts
|
||||||
|
process.bootFlags = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
delete process.bootFlags;
|
||||||
});
|
});
|
||||||
|
|
||||||
var dummyInstructions = someInstructions({
|
var dummyInstructions = someInstructions({
|
||||||
|
@ -178,7 +186,6 @@ describe('executor', function() {
|
||||||
|
|
||||||
describe('with boot and models files', function() {
|
describe('with boot and models files', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
process.bootFlags = process.bootFlags || [];
|
|
||||||
boot.execute(app, simpleAppInstructions());
|
boot.execute(app, simpleAppInstructions());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -212,14 +219,6 @@ describe('executor', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with boot with callback', function() {
|
describe('with boot with callback', function() {
|
||||||
beforeEach(function() {
|
|
||||||
process.bootFlags = process.bootFlags || [];
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
delete process.bootFlags;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should run `boot/*` files asynchronously', function(done) {
|
it('should run `boot/*` files asynchronously', function(done) {
|
||||||
boot.execute(app, simpleAppInstructions(), function() {
|
boot.execute(app, simpleAppInstructions(), function() {
|
||||||
expect(process.bootFlags).to.eql([
|
expect(process.bootFlags).to.eql([
|
||||||
|
@ -233,7 +232,6 @@ describe('executor', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with PaaS and npm env variables', function() {
|
describe('with PaaS and npm env variables', function() {
|
||||||
|
@ -326,6 +324,68 @@ describe('executor', function() {
|
||||||
boot.execute(app, someInstructions({ files: { boot: [file] } }));
|
boot.execute(app, someInstructions({ files: { boot: [file] } }));
|
||||||
expect(app.fnCalled, 'exported fn was called').to.be.true();
|
expect(app.fnCalled, 'exported fn was called').to.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('configures middleware', function(done) {
|
||||||
|
var pushNamePath = require.resolve('./helpers/push-name-middleware');
|
||||||
|
|
||||||
|
boot.execute(app, someInstructions({
|
||||||
|
middleware: {
|
||||||
|
phases: ['initial', 'custom'],
|
||||||
|
middleware: [
|
||||||
|
{
|
||||||
|
sourceFile: pushNamePath,
|
||||||
|
config: {
|
||||||
|
phase: 'initial',
|
||||||
|
params: 'initial'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceFile: pushNamePath,
|
||||||
|
config: {
|
||||||
|
phase: 'custom',
|
||||||
|
params: 'custom'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceFile: pushNamePath,
|
||||||
|
config: {
|
||||||
|
phase: 'routes',
|
||||||
|
params: 'routes'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sourceFile: pushNamePath,
|
||||||
|
config: {
|
||||||
|
phase: 'routes',
|
||||||
|
enabled: false,
|
||||||
|
params: 'disabled'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
supertest(app)
|
||||||
|
.get('/')
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) return done(err);
|
||||||
|
var names = (res.headers.names || '').split(',');
|
||||||
|
expect(names).to.eql(['initial', 'custom', 'routes']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('configures middleware (end-to-end)', function(done) {
|
||||||
|
boot.execute(app, simpleAppInstructions());
|
||||||
|
|
||||||
|
supertest(app)
|
||||||
|
.get('/')
|
||||||
|
.end(function(err, res) {
|
||||||
|
if (err) return done(err);
|
||||||
|
expect(res.headers.names).to.equal('custom-middleware');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertValidDataSource(dataSource) {
|
function assertValidDataSource(dataSource) {
|
||||||
|
@ -350,6 +410,7 @@ function someInstructions(values) {
|
||||||
config: values.config || {},
|
config: values.config || {},
|
||||||
models: values.models || [],
|
models: values.models || [],
|
||||||
dataSources: values.dataSources || { db: { connector: 'memory' } },
|
dataSources: values.dataSources || { db: { connector: 'memory' } },
|
||||||
|
middleware: values.middleware || { phases: [], middleware: [] },
|
||||||
files: {
|
files: {
|
||||||
boot: []
|
boot: []
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"initial": {
|
||||||
|
"../../helpers/push-name-middleware": {
|
||||||
|
"params": "custom-middleware"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
module.exports = function(name) {
|
||||||
|
return function(req, res, next) {
|
||||||
|
req._names = req._names || [];
|
||||||
|
req._names.push(name);
|
||||||
|
res.setHeader('names', req._names.join(','));
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue