Merge pull request #2564 from strongloop/feature/remove-current-context
[SEMVER-MAJOR] Remove current-context API
This commit is contained in:
commit
f13e584686
|
@ -153,3 +153,44 @@ We have removed `loopback#errorhandler` middleware, users should use `strong-err
|
||||||
```
|
```
|
||||||
|
|
||||||
See also strong-error-handler's [options](https://github.com/strongloop/strong-error-handler#options) and the [related code change](https://github.com/strongloop/loopback/pull/2411).
|
See also strong-error-handler's [options](https://github.com/strongloop/strong-error-handler#options) and the [related code change](https://github.com/strongloop/loopback/pull/2411).
|
||||||
|
|
||||||
|
## Remove current context API and middleware
|
||||||
|
|
||||||
|
We have removed the following current-context-related APIs:
|
||||||
|
|
||||||
|
- `loopback.getCurrentContext`
|
||||||
|
- `loopback.createContext`
|
||||||
|
- `loopback.runInContext`
|
||||||
|
|
||||||
|
Additionaly, `loopback#context` middleware and `remoting.context` server
|
||||||
|
config were removed too.
|
||||||
|
|
||||||
|
To setup "current context" feature in your LoopBack 3.x application, you
|
||||||
|
should use [loopback-context](https://www.npmjs.com/package/loopback-context)
|
||||||
|
module:
|
||||||
|
|
||||||
|
1. Add `loopback-context` to your dependencies
|
||||||
|
|
||||||
|
2. Configure the new context middleware in your `server/middleware-config.json` file
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"initial": {
|
||||||
|
"loopback-context#per-request": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Replace all usages of `loopback.getCurrentContext` with the following:
|
||||||
|
```js
|
||||||
|
// at the top of your file
|
||||||
|
var LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
|
// in your code
|
||||||
|
var ctx = LoopBackContext.getCurrentContext();
|
||||||
|
if (ctx) {
|
||||||
|
// use the context
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See also [loopback#2564](https://github.com/strongloop/loopback/pull/2564)
|
||||||
|
and the official [documentation](https://docs.strongloop.com/display/APIC/Using+current+context)
|
||||||
|
|
|
@ -40,9 +40,6 @@ module.exports = function(grunt) {
|
||||||
common: {
|
common: {
|
||||||
src: ['common/**/*.js'],
|
src: ['common/**/*.js'],
|
||||||
},
|
},
|
||||||
browser: {
|
|
||||||
src: ['browser/**/*.js'],
|
|
||||||
},
|
|
||||||
server: {
|
server: {
|
||||||
src: ['server/**/*.js'],
|
src: ['server/**/*.js'],
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright IBM Corp. 2015. All Rights Reserved.
|
|
||||||
// Node module: loopback
|
|
||||||
// This file is licensed under the MIT License.
|
|
||||||
// License text available at https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
var g = require('strong-globalize')();
|
|
||||||
|
|
||||||
module.exports = function(loopback) {
|
|
||||||
loopback.getCurrentContext = function() {
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
loopback.runInContext =
|
|
||||||
loopback.createContext = function() {
|
|
||||||
throw new Error(g.f('Current context is not supported in the browser.'));
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||||
|
// Node module: loopback
|
||||||
|
// This file is licensed under the MIT License.
|
||||||
|
// License text available at https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
var g = require('strong-globalize')();
|
||||||
|
var juggler = require('loopback-datasource-juggler');
|
||||||
|
var remoting = require('strong-remoting');
|
||||||
|
|
||||||
|
module.exports = function(loopback) {
|
||||||
|
juggler.getCurrentContext =
|
||||||
|
remoting.getCurrentContext =
|
||||||
|
loopback.getCurrentContext = function() {
|
||||||
|
throw new Error(g.f(
|
||||||
|
'%s was removed in version 3.0. See %s for more details.',
|
||||||
|
'loopback.getCurrentContext()',
|
||||||
|
'https://docs.strongloop.com/display/APIC/Using%20current%20context'));
|
||||||
|
};
|
||||||
|
|
||||||
|
loopback.runInContext = function(fn) {
|
||||||
|
throw new Error(g.f(
|
||||||
|
'%s was removed in version 3.0. See %s for more details.',
|
||||||
|
'loopback.runInContext()',
|
||||||
|
'https://docs.strongloop.com/display/APIC/Using%20current%20context'));
|
||||||
|
};
|
||||||
|
|
||||||
|
loopback.createContext = function(scopeName) {
|
||||||
|
throw new Error(g.f(
|
||||||
|
'%s was removed in version 3.0. See %s for more details.',
|
||||||
|
'loopback.createContext()',
|
||||||
|
'https://docs.strongloop.com/display/APIC/Using%20current%20context'));
|
||||||
|
};
|
||||||
|
};
|
|
@ -200,7 +200,7 @@ loopback.template = function(file) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
require('../server/current-context')(loopback);
|
require('../lib/current-context')(loopback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a named vanilla JavaScript class constructor with an attached
|
* Create a named vanilla JavaScript class constructor with an attached
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
"bluebird": "^3.1.1",
|
"bluebird": "^3.1.1",
|
||||||
"body-parser": "^1.12.0",
|
"body-parser": "^1.12.0",
|
||||||
"canonical-json": "0.0.4",
|
"canonical-json": "0.0.4",
|
||||||
"continuation-local-storage": "^3.1.3",
|
|
||||||
"debug": "^2.1.2",
|
"debug": "^2.1.2",
|
||||||
"depd": "^1.0.0",
|
"depd": "^1.0.0",
|
||||||
"ejs": "^2.3.1",
|
"ejs": "^2.3.1",
|
||||||
|
@ -82,6 +81,7 @@
|
||||||
"karma-phantomjs-launcher": "^1.0.0",
|
"karma-phantomjs-launcher": "^1.0.0",
|
||||||
"karma-script-launcher": "^1.0.0",
|
"karma-script-launcher": "^1.0.0",
|
||||||
"loopback-boot": "^2.7.0",
|
"loopback-boot": "^2.7.0",
|
||||||
|
"loopback-context": "^1.0.0",
|
||||||
"mocha": "^3.0.0",
|
"mocha": "^3.0.0",
|
||||||
"phantomjs-prebuilt": "^2.1.7",
|
"phantomjs-prebuilt": "^2.1.7",
|
||||||
"sinon": "^1.13.0",
|
"sinon": "^1.13.0",
|
||||||
|
@ -97,7 +97,6 @@
|
||||||
"browser": {
|
"browser": {
|
||||||
"express": "./lib/browser-express.js",
|
"express": "./lib/browser-express.js",
|
||||||
"./lib/server-app.js": "./lib/browser-express.js",
|
"./lib/server-app.js": "./lib/browser-express.js",
|
||||||
"./server/current-context.js": "./browser/current-context.js",
|
|
||||||
"connect": false,
|
"connect": false,
|
||||||
"nodemailer": false,
|
"nodemailer": false,
|
||||||
"supertest": false,
|
"supertest": false,
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
|
||||||
// Node module: loopback
|
|
||||||
// This file is licensed under the MIT License.
|
|
||||||
// License text available at https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
var juggler = require('loopback-datasource-juggler');
|
|
||||||
var remoting = require('strong-remoting');
|
|
||||||
var cls = require('continuation-local-storage');
|
|
||||||
var domain = require('domain');
|
|
||||||
|
|
||||||
module.exports = function(loopback) {
|
|
||||||
/**
|
|
||||||
* Get the current context object. The context is preserved
|
|
||||||
* across async calls, it behaves like a thread-local storage.
|
|
||||||
*
|
|
||||||
* @returns {ChainedContext} The context object or null.
|
|
||||||
*/
|
|
||||||
loopback.getCurrentContext = function() {
|
|
||||||
// A placeholder method, see loopback.createContext() for the real version
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the given function in such way that
|
|
||||||
* `loopback.getCurrentContext` returns the
|
|
||||||
* provided context object.
|
|
||||||
*
|
|
||||||
* **NOTE**
|
|
||||||
*
|
|
||||||
* The method is supported on the server only, it does not work
|
|
||||||
* in the browser at the moment.
|
|
||||||
*
|
|
||||||
* @param {Function} fn The function to run, it will receive arguments
|
|
||||||
* (currentContext, currentDomain).
|
|
||||||
* @param {ChainedContext} context An optional context object.
|
|
||||||
* When no value is provided, then the default global context is used.
|
|
||||||
*/
|
|
||||||
loopback.runInContext = function(fn, context) {
|
|
||||||
var currentDomain = domain.create();
|
|
||||||
currentDomain.oldBind = currentDomain.bind;
|
|
||||||
currentDomain.bind = function(callback, context) {
|
|
||||||
return currentDomain.oldBind(ns.bind(callback, context), context);
|
|
||||||
};
|
|
||||||
|
|
||||||
var ns = context || loopback.createContext('loopback');
|
|
||||||
|
|
||||||
currentDomain.run(function() {
|
|
||||||
ns.run(function executeInContext(context) {
|
|
||||||
fn(ns, currentDomain);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LoopBackContext instance that can be used
|
|
||||||
* for `loopback.runInContext`.
|
|
||||||
*
|
|
||||||
* **NOTES**
|
|
||||||
*
|
|
||||||
* At the moment, `loopback.getCurrentContext` supports
|
|
||||||
* a single global context instance only. If you call `createContext()`
|
|
||||||
* multiple times, `getCurrentContext` will return the last context
|
|
||||||
* created.
|
|
||||||
*
|
|
||||||
* The method is supported on the server only, it does not work
|
|
||||||
* in the browser at the moment.
|
|
||||||
*
|
|
||||||
* @param {String} scopeName An optional scope name.
|
|
||||||
* @return {ChainedContext} The new context object.
|
|
||||||
*/
|
|
||||||
loopback.createContext = function(scopeName) {
|
|
||||||
// Make the namespace globally visible via the process.context property
|
|
||||||
process.context = process.context || {};
|
|
||||||
var ns = process.context[scopeName];
|
|
||||||
if (!ns) {
|
|
||||||
ns = cls.createNamespace(scopeName);
|
|
||||||
process.context[scopeName] = ns;
|
|
||||||
// Set up loopback.getCurrentContext()
|
|
||||||
loopback.getCurrentContext = function() {
|
|
||||||
return ns && ns.active ? ns : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
chain(juggler);
|
|
||||||
chain(remoting);
|
|
||||||
}
|
|
||||||
return ns;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a chained context
|
|
||||||
* @param {Object} child The child context
|
|
||||||
* @param {Object} parent The parent context
|
|
||||||
* @private
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function ChainedContext(child, parent) {
|
|
||||||
this.child = child;
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value by name from the context. If it doesn't exist in the child
|
|
||||||
* context, try the parent one
|
|
||||||
* @param {String} name Name of the context property
|
|
||||||
* @returns {*} Value of the context property
|
|
||||||
*/
|
|
||||||
ChainedContext.prototype.get = function(name) {
|
|
||||||
var val = this.child && this.child.get(name);
|
|
||||||
if (val === undefined) {
|
|
||||||
return this.parent && this.parent.get(name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainedContext.prototype.set = function(name, val) {
|
|
||||||
if (this.child) {
|
|
||||||
return this.child.set(name, val);
|
|
||||||
} else {
|
|
||||||
return this.parent && this.parent.set(name, val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ChainedContext.prototype.reset = function(name, val) {
|
|
||||||
if (this.child) {
|
|
||||||
return this.child.reset(name, val);
|
|
||||||
} else {
|
|
||||||
return this.parent && this.parent.reset(name, val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function chain(child) {
|
|
||||||
if (typeof child.getCurrentContext === 'function') {
|
|
||||||
var childContext = new ChainedContext(child.getCurrentContext(),
|
|
||||||
loopback.getCurrentContext());
|
|
||||||
child.getCurrentContext = function() {
|
|
||||||
return childContext;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
child.getCurrentContext = loopback.getCurrentContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -3,55 +3,9 @@
|
||||||
// This file is licensed under the MIT License.
|
// This file is licensed under the MIT License.
|
||||||
// License text available at https://opensource.org/licenses/MIT
|
// License text available at https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
var loopback = require('../../lib/loopback');
|
module.exports = function() {
|
||||||
|
throw new Error(g.f(
|
||||||
module.exports = context;
|
'%s middleware was removed in version 3.0. See %s for more details.',
|
||||||
|
'loopback#context',
|
||||||
var name = 'loopback';
|
'https://docs.strongloop.com/display/APIC/Using%20current%20context'));
|
||||||
|
|
||||||
/**
|
|
||||||
* Context middleware.
|
|
||||||
* ```js
|
|
||||||
* var app = loopback();
|
|
||||||
* app.use(loopback.context(options);
|
|
||||||
* app.use(loopback.rest());
|
|
||||||
* app.listen();
|
|
||||||
* ```
|
|
||||||
* @options {Object} [options] Options for context
|
|
||||||
* @property {String} name Context scope name.
|
|
||||||
* @property {Boolean} enableHttpContext Whether HTTP context is enabled. Default is false.
|
|
||||||
* @header loopback.context([options])
|
|
||||||
*/
|
|
||||||
|
|
||||||
function context(options) {
|
|
||||||
options = options || {};
|
|
||||||
var scope = options.name || name;
|
|
||||||
var enableHttpContext = options.enableHttpContext || false;
|
|
||||||
var ns = loopback.createContext(scope);
|
|
||||||
|
|
||||||
// Return the middleware
|
|
||||||
return function contextHandler(req, res, next) {
|
|
||||||
if (req.loopbackContext) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
loopback.runInContext(function processRequestInContext(ns, domain) {
|
|
||||||
req.loopbackContext = ns;
|
|
||||||
|
|
||||||
// Bind req/res event emitters to the given namespace
|
|
||||||
ns.bindEmitter(req);
|
|
||||||
ns.bindEmitter(res);
|
|
||||||
|
|
||||||
// Add req/res event emitters to the current domain
|
|
||||||
domain.add(req);
|
|
||||||
domain.add(res);
|
|
||||||
|
|
||||||
// Run the code in the context of the namespace
|
|
||||||
if (enableHttpContext) {
|
|
||||||
// Set up the transport context
|
|
||||||
ns.set('http', { req: req, res: res });
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
var loopback = require('../../lib/loopback');
|
var loopback = require('../../lib/loopback');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var deprecate = require('depd')('loopback');
|
var g = require('strong-globalize')();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Export the middleware.
|
* Export the middleware.
|
||||||
|
@ -40,11 +40,11 @@ function rest() {
|
||||||
var remotingOptions = app.get('remoting') || {};
|
var remotingOptions = app.get('remoting') || {};
|
||||||
|
|
||||||
var contextOptions = remotingOptions.context;
|
var contextOptions = remotingOptions.context;
|
||||||
if (contextOptions !== false) {
|
if (contextOptions !== undefined && contextOptions !== false) {
|
||||||
if (typeof contextOptions !== 'object') {
|
throw new Error(g.f(
|
||||||
contextOptions = {};
|
'%s was removed in version 3.0. See %s for more details.',
|
||||||
}
|
'remoting.context option',
|
||||||
handlers.push(loopback.context(contextOptions));
|
'https://docs.strongloop.com/display/APIC/Using%20current%20context'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.isAuthEnabled) {
|
if (app.isAuthEnabled) {
|
||||||
|
|
|
@ -124,7 +124,7 @@ function token(options) {
|
||||||
TokenModel.findForRequest(req, options, function(err, token) {
|
TokenModel.findForRequest(req, options, function(err, token) {
|
||||||
req.accessToken = token || null;
|
req.accessToken = token || null;
|
||||||
rewriteUserLiteral(req, currentUserLiteral);
|
rewriteUserLiteral(req, currentUserLiteral);
|
||||||
var ctx = loopback.getCurrentContext();
|
var ctx = req.loopbackContext;
|
||||||
if (ctx) ctx.set('accessToken', token);
|
if (ctx) ctx.set('accessToken', token);
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
// License text available at https://opensource.org/licenses/MIT
|
// License text available at https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
var cookieParser = require('cookie-parser');
|
var cookieParser = require('cookie-parser');
|
||||||
|
var LoopBackContext = require('loopback-context');
|
||||||
|
var contextMiddleware = require('loopback-context').perRequest;
|
||||||
var loopback = require('../');
|
var loopback = require('../');
|
||||||
var extend = require('util')._extend;
|
var extend = require('util')._extend;
|
||||||
var Token = loopback.AccessToken.extend('MyToken');
|
var Token = loopback.AccessToken.extend('MyToken');
|
||||||
|
@ -477,7 +479,8 @@ describe('app.enableAuth()', function() {
|
||||||
it('stores token in the context', function(done) {
|
it('stores token in the context', function(done) {
|
||||||
var TestModel = loopback.createModel('TestModel', { base: 'Model' });
|
var TestModel = loopback.createModel('TestModel', { base: 'Model' });
|
||||||
TestModel.getToken = function(cb) {
|
TestModel.getToken = function(cb) {
|
||||||
cb(null, loopback.getCurrentContext().get('accessToken') || null);
|
var ctx = LoopBackContext.getCurrentContext();
|
||||||
|
cb(null, ctx && ctx.get('accessToken') || null);
|
||||||
};
|
};
|
||||||
TestModel.remoteMethod('getToken', {
|
TestModel.remoteMethod('getToken', {
|
||||||
returns: { arg: 'token', type: 'object' },
|
returns: { arg: 'token', type: 'object' },
|
||||||
|
@ -488,7 +491,7 @@ describe('app.enableAuth()', function() {
|
||||||
app.model(TestModel, { dataSource: null });
|
app.model(TestModel, { dataSource: null });
|
||||||
|
|
||||||
app.enableAuth();
|
app.enableAuth();
|
||||||
app.use(loopback.context());
|
app.use(contextMiddleware());
|
||||||
app.use(loopback.token({ model: Token }));
|
app.use(loopback.token({ model: Token }));
|
||||||
app.use(loopback.rest());
|
app.use(loopback.rest());
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"remoting": {
|
"remoting": {
|
||||||
"context": {
|
|
||||||
"enableHttpContext": false
|
|
||||||
},
|
|
||||||
"rest": {
|
"rest": {
|
||||||
"normalizeHttpPath": false,
|
"normalizeHttpPath": false,
|
||||||
"xml": false
|
"xml": false
|
||||||
|
|
|
@ -518,91 +518,6 @@ describe('loopback', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.onServer('loopback.getCurrentContext', function() {
|
|
||||||
var runInOtherDomain, runnerInterval;
|
|
||||||
|
|
||||||
before(function setupRunInOtherDomain() {
|
|
||||||
var emitterInOtherDomain = new EventEmitter();
|
|
||||||
Domain.create().add(emitterInOtherDomain);
|
|
||||||
|
|
||||||
runInOtherDomain = function(fn) {
|
|
||||||
emitterInOtherDomain.once('run', fn);
|
|
||||||
};
|
|
||||||
|
|
||||||
runnerInterval = setInterval(function() {
|
|
||||||
emitterInOtherDomain.emit('run');
|
|
||||||
}, 10);
|
|
||||||
});
|
|
||||||
|
|
||||||
after(function tearDownRunInOtherDomain() {
|
|
||||||
clearInterval(runnerInterval);
|
|
||||||
});
|
|
||||||
|
|
||||||
// See the following two items for more details:
|
|
||||||
// https://github.com/strongloop/loopback/issues/809
|
|
||||||
// https://github.com/strongloop/loopback/pull/337#issuecomment-61680577
|
|
||||||
it('preserves callback domain', function(done) {
|
|
||||||
var app = loopback();
|
|
||||||
app.use(loopback.rest());
|
|
||||||
app.dataSource('db', { connector: 'memory' });
|
|
||||||
|
|
||||||
var TestModel = loopback.createModel({ name: 'TestModel' });
|
|
||||||
app.model(TestModel, { dataSource: 'db', public: true });
|
|
||||||
|
|
||||||
// function for remote method
|
|
||||||
TestModel.test = function(inst, cb) {
|
|
||||||
var tmpCtx = loopback.getCurrentContext();
|
|
||||||
if (tmpCtx) tmpCtx.set('data', 'a value stored in context');
|
|
||||||
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
|
|
||||||
runInOtherDomain(cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
// remote method
|
|
||||||
TestModel.remoteMethod('test', {
|
|
||||||
accepts: { arg: 'inst', type: uniqueModelName },
|
|
||||||
returns: { root: true },
|
|
||||||
http: { path: '/test', verb: 'get' },
|
|
||||||
});
|
|
||||||
|
|
||||||
// after remote hook
|
|
||||||
TestModel.afterRemote('**', function(ctxx, inst, next) {
|
|
||||||
var tmpCtx = loopback.getCurrentContext();
|
|
||||||
if (tmpCtx) {
|
|
||||||
ctxx.result.data = tmpCtx.get('data');
|
|
||||||
} else {
|
|
||||||
ctxx.result.data = 'context not available';
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
request(app)
|
|
||||||
.get('/TestModels/test')
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) return done(err);
|
|
||||||
|
|
||||||
expect(res.body.data).to.equal('a value stored in context');
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('works outside REST middleware', function(done) {
|
|
||||||
loopback.runInContext(function() {
|
|
||||||
var ctx = loopback.getCurrentContext();
|
|
||||||
expect(ctx).is.an('object');
|
|
||||||
ctx.set('test-key', 'test-value');
|
|
||||||
process.nextTick(function() {
|
|
||||||
var ctx = loopback.getCurrentContext();
|
|
||||||
expect(ctx).is.an('object');
|
|
||||||
expect(ctx.get('test-key')).to.equal('test-value');
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('new remote method configuration', function() {
|
describe('new remote method configuration', function() {
|
||||||
function getAllMethodNamesWithoutClassName(TestModel) {
|
function getAllMethodNamesWithoutClassName(TestModel) {
|
||||||
return TestModel.sharedClass.methods().map(function(m) {
|
return TestModel.sharedClass.methods().map(function(m) {
|
||||||
|
|
|
@ -197,111 +197,6 @@ describe('loopback.rest', function() {
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('context propagation', function() {
|
|
||||||
var User;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
User = givenUserModelWithAuth();
|
|
||||||
User.getToken = function(cb) {
|
|
||||||
var context = loopback.getCurrentContext();
|
|
||||||
var req = context.get('http').req;
|
|
||||||
expect(req).to.have.property('accessToken');
|
|
||||||
|
|
||||||
var juggler = require('loopback-datasource-juggler');
|
|
||||||
expect(juggler.getCurrentContext().get('http').req)
|
|
||||||
.to.have.property('accessToken');
|
|
||||||
|
|
||||||
var remoting = require('strong-remoting');
|
|
||||||
expect(remoting.getCurrentContext().get('http').req)
|
|
||||||
.to.have.property('accessToken');
|
|
||||||
|
|
||||||
cb(null, req && req.accessToken ? req.accessToken.id : null);
|
|
||||||
};
|
|
||||||
// Set up the ACL
|
|
||||||
User.settings.acls.push({ principalType: 'ROLE',
|
|
||||||
principalId: '$authenticated', permission: 'ALLOW',
|
|
||||||
property: 'getToken' });
|
|
||||||
|
|
||||||
loopback.remoteMethod(User.getToken, {
|
|
||||||
accepts: [],
|
|
||||||
returns: [
|
|
||||||
{ type: 'object', name: 'id' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function invokeGetToken(done) {
|
|
||||||
givenLoggedInUser(function(err, token) {
|
|
||||||
if (err) return done(err);
|
|
||||||
|
|
||||||
request(app).get('/users/getToken')
|
|
||||||
.set('Authorization', token.id)
|
|
||||||
.expect(200)
|
|
||||||
.end(function(err, res) {
|
|
||||||
if (err) return done(err);
|
|
||||||
|
|
||||||
expect(res.body.id).to.equal(token.id);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should enable context using loopback.context', function(done) {
|
|
||||||
app.use(loopback.context({ enableHttpContext: true }));
|
|
||||||
app.enableAuth({ dataSource: 'db' });
|
|
||||||
app.use(loopback.rest());
|
|
||||||
|
|
||||||
invokeGetToken(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should enable context with loopback.rest', function(done) {
|
|
||||||
app.enableAuth({ dataSource: 'db' });
|
|
||||||
app.set('remoting', { context: { enableHttpContext: true }});
|
|
||||||
app.use(loopback.rest());
|
|
||||||
|
|
||||||
invokeGetToken(done);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support explicit context', function(done) {
|
|
||||||
app.enableAuth({ dataSource: 'db' });
|
|
||||||
app.use(loopback.context());
|
|
||||||
app.use(loopback.token(
|
|
||||||
{ model: app.registry.getModelByType('AccessToken') }));
|
|
||||||
app.use(function(req, res, next) {
|
|
||||||
loopback.getCurrentContext().set('accessToken', req.accessToken);
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
app.use(loopback.rest());
|
|
||||||
|
|
||||||
User.getToken = function(cb) {
|
|
||||||
var context = loopback.getCurrentContext();
|
|
||||||
var accessToken = context.get('accessToken');
|
|
||||||
expect(context.get('accessToken')).to.have.property('id');
|
|
||||||
|
|
||||||
var juggler = require('loopback-datasource-juggler');
|
|
||||||
context = juggler.getCurrentContext();
|
|
||||||
expect(context.get('accessToken')).to.have.property('id');
|
|
||||||
|
|
||||||
var remoting = require('strong-remoting');
|
|
||||||
context = remoting.getCurrentContext();
|
|
||||||
expect(context.get('accessToken')).to.have.property('id');
|
|
||||||
|
|
||||||
cb(null, accessToken ? accessToken.id : null);
|
|
||||||
};
|
|
||||||
|
|
||||||
loopback.remoteMethod(User.getToken, {
|
|
||||||
accepts: [],
|
|
||||||
returns: [
|
|
||||||
{ type: 'object', name: 'id' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
invokeGetToken(done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function givenUserModelWithAuth() {
|
function givenUserModelWithAuth() {
|
||||||
var AccessToken = app.registry.getModel('AccessToken');
|
var AccessToken = app.registry.getModel('AccessToken');
|
||||||
app.model(AccessToken, { dataSource: 'db' });
|
app.model(AccessToken, { dataSource: 'db' });
|
||||||
|
|
Loading…
Reference in New Issue