Merge branch 'release/1.3.3' into production

This commit is contained in:
Raymond Feng 2013-12-06 10:47:55 -08:00
commit 8cf84c3581
4 changed files with 146 additions and 5 deletions

View File

@ -32,8 +32,8 @@ The options argument is a JSON object, described in the following table.
| Option | Required? | Description | | Option | Required? | Description |
| ----- | ----- | ----- | | ----- | ----- | ----- |
| accepts | No | Describes the remote method's arguments, as explained <a href="#argdesc">below</a>. The callback is an assumed argument; do not specify. | | accepts | No | Describes the remote method's arguments; See <a href="#argdesc">Argument description</a>. The `callback` argument is assumed; do not specify. |
| returns | No | Describes the remote method's callback arguments, as explained <a href="#argdesc">below</a>.. The err argument is assumed; do not specify. | | returns | No | Describes the remote method's callback arguments; See <a href="#argdesc">Argument description</a>. The `err` argument is assumed; do not specify. |
| http | No | HTTP routing information: <ul><li> **http.path**: path (relative to the model) at which the method is exposed. May be a path fragment (for example, `/:myArg`) that will be populated by an arg of the same name in the `accepts` description. For example, the `stats` method above will be at the whole path `/products/stats`.</li><li> **http.verb**: HTTP method (verb) from which the method is available (one of: get, post, put, del, or all).</li></ul> | http | No | HTTP routing information: <ul><li> **http.path**: path (relative to the model) at which the method is exposed. May be a path fragment (for example, `/:myArg`) that will be populated by an arg of the same name in the `accepts` description. For example, the `stats` method above will be at the whole path `/products/stats`.</li><li> **http.verb**: HTTP method (verb) from which the method is available (one of: get, post, put, del, or all).</li></ul>
<a name="argdesc"></a> <a name="argdesc"></a>
@ -42,8 +42,13 @@ The options argument is a JSON object, described in the following table.
The arguments description defines either a single argument as an object or an ordered set of arguments as an array. Each individual argument has keys for: The arguments description defines either a single argument as an object or an ordered set of arguments as an array. Each individual argument has keys for:
* arg: argument name * arg: argument name
* type: argument datatype; must be a[loopback type](http://wiki.strongloop.com/display/DOC/LoopBack+types). * type: argument datatype; must be a [loopback type](http://wiki.strongloop.com/display/DOC/LoopBack+types).
* required: Boolean value indicating if argument is required. * required: Boolean value indicating if argument is required.
* root: For callback arguments: set this property to `true` if your function
has a single callback argument to use as the root object
returned to remote caller. Otherwise the root object returned is a map (argument-name to argument-value).
* http: For input arguments: a function or an object describing mapping from HTTP request
to the argument value, as explained <a href="#argdesc-http">below</a>.
For example, a single argument, specified as an object: For example, a single argument, specified as an object:
@ -60,6 +65,58 @@ Multiple arguments, specified as an array:
] ]
``` ```
<a name="argdesc-http"></a>
**HTTP mapping of input arguments**
There are two ways to specify HTTP mapping for input parameters (what the method accepts):
* Provide an object with a `source` property
* Specify a custom mapping function
To use the first way to specify HTTP mapping for input parameters, provide an object with a `source` property
that has one of the values shown in the following table.
| Value of source property | Description |
|---|---|
| body | The whole request body is used as the value. |
| form | The value is looked up using `req.param`, which searches route arguments, the request body and the query string.|
| query | An alias for form (see above). |
| path | An alias for form (see above). |
| req | The whole HTTP reqest object is used as the value. |
For example, an argument getting the whole request body as the value:
```js
{ arg: 'data', type: 'object', http: { source: 'body' } }
```
The use the second way to specify HTTP mapping for input parameters, specify a custom mapping function
that looks like this:
```js
{
arg: 'custom',
type: 'number',
http: function(ctx) {
// ctx is LoopBack Context object
// 1. Get the HTTP request object as provided by Express
var req = ctx.req;
// 2. Get 'a' and 'b' from query string or form data
// and return their sum as the value
return +req.param('a') + req.param('b');
}
}
```
If you don't specify a mapping, LoopBack will determine the value
as follows (assuming `name` as the name of the input parameter to resolve):
1. If there is a HTTP request parameter `args` with a JSON content,
then the value of `args['name']` is used if it is defined.
2. Otherwise `req.param('name')` is returned.
## Remote hooks ## Remote hooks
Run a function before or after a remote method is called by a client. Run a function before or after a remote method is called by a client.

View File

@ -231,6 +231,25 @@ app.boot = function(options) {
assertIsValidConfig('model', modelConfig); assertIsValidConfig('model', modelConfig);
assertIsValidConfig('data source', dataSourceConfig); assertIsValidConfig('data source', dataSourceConfig);
appConfig.host =
process.env.npm_config_host ||
process.env.OPENSHIFT_SLS_IP ||
process.env.OPENSHIFT_NODEJS_IP ||
process.env.HOST ||
appConfig.host ||
process.env.npm_package_config_host ||
app.get('host');
appConfig.port =
process.env.npm_config_port ||
process.env.OPENSHIFT_SLS_PORT ||
process.env.OPENSHIFT_NODEJS_PORT ||
process.env.PORT ||
appConfig.port ||
process.env.npm_package_config_port ||
app.get('port') ||
3000;
if(appConfig.host !== undefined) { if(appConfig.host !== undefined) {
assert(typeof appConfig.host === 'string', 'app.host must be a string'); assert(typeof appConfig.host === 'string', 'app.host must be a string');
app.set('host', appConfig.host); app.set('host', appConfig.host);

View File

@ -9,14 +9,13 @@
"Platform", "Platform",
"mBaaS" "mBaaS"
], ],
"version": "1.3.1", "version": "1.3.3",
"scripts": { "scripts": {
"test": "mocha -R spec" "test": "mocha -R spec"
}, },
"dependencies": { "dependencies": {
"debug": "~0.7.2", "debug": "~0.7.2",
"express": "~3.4.0", "express": "~3.4.0",
"loopback-datasource-juggler": "~1.2.0",
"strong-remoting": "~1.1.0", "strong-remoting": "~1.1.0",
"inflection": "~1.2.5", "inflection": "~1.2.5",
"passport": "~0.1.17", "passport": "~0.1.17",
@ -29,7 +28,11 @@
"uid2": "0.0.3", "uid2": "0.0.3",
"async": "~0.2.9" "async": "~0.2.9"
}, },
"peerDependencies": {
"loopback-datasource-juggler": "~1.2.0"
},
"devDependencies": { "devDependencies": {
"loopback-datasource-juggler": "~1.2.0",
"mocha": "~1.14.0", "mocha": "~1.14.0",
"strong-task-emitter": "0.0.x", "strong-task-emitter": "0.0.x",
"supertest": "~0.8.1" "supertest": "~0.8.1"

View File

@ -77,6 +77,68 @@ describe('app', function() {
assert.equal(this.app.get('host'), '127.0.0.1'); assert.equal(this.app.get('host'), '127.0.0.1');
}); });
describe('PaaS and npm env variables', function() {
beforeEach(function() {
this.boot = function () {
var app = loopback();
app.boot({
app: {
port: undefined,
host: undefined
}
});
return app;
}
});
it('should be honored', function() {
var assertHonored = function (portKey, hostKey) {
process.env[hostKey] = randomPort();
process.env[portKey] = randomHost();
var app = this.boot();
assert.equal(app.get('port'), process.env[portKey]);
assert.equal(app.get('host'), process.env[hostKey]);
delete process.env[portKey];
delete process.env[hostKey];
}.bind(this);
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_NODEJS_IP');
assertHonored('npm_config_port', 'npm_config_host');
assertHonored('npm_package_config_port', 'npm_package_config_host');
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_SLS_IP');
assertHonored('PORT', 'HOST');
});
it('should be honored in order', function() {
process.env.npm_config_host = randomHost();
process.env.OPENSHIFT_SLS_IP = randomHost();
process.env.OPENSHIFT_NODEJS_IP = randomHost();
process.env.HOST = randomHost();
process.env.npm_package_config_host = randomHost();
var app = this.boot();
assert.equal(app.get('host'), process.env.npm_config_host);
process.env.npm_config_port = randomPort();
process.env.OPENSHIFT_SLS_PORT = randomPort();
process.env.OPENSHIFT_NODEJS_PORT = randomPort();
process.env.PORT = randomPort();
process.env.npm_package_config_port = randomPort();
var app = this.boot();
assert.equal(app.get('host'), process.env.npm_config_host);
assert.equal(app.get('port'), process.env.npm_config_port);
});
function randomHost() {
return Math.random().toString().split('.')[1];
}
function randomPort() {
return Math.floor(Math.random() * 10000);
}
});
it('Instantiate models', function () { it('Instantiate models', function () {
assert(app.models); assert(app.models);
assert(app.models.FooBarBatBaz); assert(app.models.FooBarBatBaz);