Giter Club home page Giter Club logo

loopback's Introduction

LoopBack

Gitter Module LTS Adopted' IBM Support

โš ๏ธ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing support for community users. The only exception is fixes for critical bugs and security vulnerabilities provided as part of support for IBM API Connect customers. We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as soon as possible. Learn more about LoopBack's long term support policy. will be provided or accepted. (See Module Long Term Support Policy below.)

We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as soon as possible. Refer to our Migration Guide for more information on how to upgrade.

Overview

LoopBack is a highly-extensible, open-source Node.js framework that enables you to:

  • Create dynamic end-to-end REST APIs with little or no coding.
  • Access data from Oracle, MySQL, PostgreSQL, MS SQL Server, MongoDB, SOAP and other REST APIs.
  • Incorporate model relationships and access controls for complex APIs.
  • Use built-in push, geolocation, and file services for mobile apps.
  • Easily create client apps using Android, iOS, and JavaScript SDKs.
  • Run your application on-premises or in the cloud.

LoopBack consists of:

  • A library of Node.js modules.
  • Yeoman generators for scaffolding applications.
  • Client SDKs for iOS, Android, and web clients.

LoopBack tools include:

  • Command-line tool loopback-cli to create applications, models, data sources, and so on.

For more details, see https://loopback.io/.

Module Long Term Support Policy

LoopBack 3.x has reached End-of-Life.

This module adopts the Module Long Term Support (LTS) policy, with the following End Of Life (EOL) dates:

Version Status Published EOL
LoopBack 4 Current Oct 2018 Apr 2023 (minimum)
LoopBack 3 End-of-Life Dec 2016 Dec 2020
LoopBack 2 End-of-Life Jul 2014 Apr 2019

Learn more about our LTS plan in docs.

LoopBack modules

The LoopBack framework is a set of Node.js modules that you can use independently or together.

LoopBack modules

Core

Connectors

Enterprise Connectors

Community Connectors

The LoopBack community has created and supports a number of additional connectors. See Community connectors for details.

Components

Client SDKs

Tools

Examples

StrongLoop provides a number of example applications that illustrate various key LoopBack features. In some cases, they have accompanying step-by-step instructions (tutorials).

See examples at loopback.io for details.

Resources

Contributing

Contributions to the LoopBack project are welcome! See Contributing to LoopBack for more information.

Reporting issues

One of the easiest ways to contribute to LoopBack is to report an issue. See Reporting issues for more information.

Analytics

loopback's People

Contributors

0candy avatar alfred-nsh avatar altsang avatar amir-61 avatar bajtos avatar candytangnb avatar cgole avatar clark0x avatar crandmck avatar davidcheung avatar dhmlau avatar ebarault avatar esco avatar fabien avatar greaterweb avatar haio avatar jannyhou avatar loay avatar nabdelgadir avatar pradnyabaviskar avatar raymondfeng avatar rhalff avatar ritch avatar rmg avatar seabaylea avatar simonhoibm avatar strml avatar supasate avatar superkhau avatar virkt25 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loopback's Issues

problem accessing my datasource and/or API explorer after moving from LB 1.2 to 1.4

I use the following data source code to wire up my model definitions to my oracle db:

var nodeEnv = process.env.NODE_ENV || 'demo';
var cInst = require('rc')('loopback',{
  name: 'bacn-icar',
  env: nodeEnv
});
var config = cInst[nodeEnv]['oracle'];
var ds = loopback.createDataSource(config);

I recently updated LoopBack from 1.2 to 1.4 and my api explorer stopped working so I updated my app.js to try and get it working. Now the explorer ui comes up but the rest calls are failing. The response from the server for an api call looks like the following:

{
  "error": {
    "name": "TypeError",
    "status": 500,
    "message": "Object function ModelConstructor(data, dataSource) {\n            if(!(this instanceof ModelConstructor)) {\n                return new ModelConstructor(data, dataSource);\n            }\n            if(ModelClass.settings.unresolved) {\n                throw new Error('Model ' + ModelClass.modelName + ' is not defined.');\n            }\n            ModelBaseClass.apply(this, arguments);\n            if(dataSource) {\n                hiddenProperty(this, '__dataSource', dataSource);\n            }\n        } has no method 'find'",
    "stack": "TypeError: Object function ModelConstructor(data, dataSource) {\n            if(!(this instanceof ModelConstructor)) {\n                return new ModelConstructor(data, dataSource);\n            }\n            if(ModelClass.settings.unresolved) {\n                throw new Error('Model ' + ModelClass.modelName + ' is not defined.');\n            }\n            ModelBaseClass.apply(this, arguments);\n            if(dataSource) {\n                hiddenProperty(this, '__dataSource', dataSource);\n            }\n        } has no method 'find'\n    at Function.ACL.checkAccess (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/models/acl.js:366:7)\n    at Function.ACL.checkAccessForToken (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/models/acl.js:440:7)\n    at Function.Model.checkAccess (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/models/model.js:139:7)\n    at Function.app.enableAuth (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/application.js:168:13)\n    at execStack (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:285:11)\n    at RemoteObjects.execHooks (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:291:10)\n    at RemoteObjects.invokeMethodInContext (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:413:8)\n    at async.series.results (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/async/lib/async.js:548:21)\n    at _asyncMap (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/async/lib/async.js:224:13)\n    at async.eachSeries.iterate (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/node_modules/async/lib/async.js:131:13)"
  }
}

stepping through the server code I and up in acl.js on line 366:

ACL.find({where: {model: model.modelName, property: propertyQuery,
    accessType: accessTypeQuery}}, function (err, acls) {
...
});

basically as follows:

throw new Error('Model ' + ModelClass.modelName + ' is not defined.');\n            }\n            ModelBaseClass.apply(this, arguments);\n            if(dataSource) {\n                hiddenProperty(this, '__dataSource', dataSource);\n            }\n        } has no method 'find'\n    at Function.ACL.checkAccess (/Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/models/acl.js:366:

My guess is some kind of ACL configuration is required...back to the docs.

ACL Permission Precedence

/to @raymondfeng

Given the following ACL and a request to POST /myModel (MyModel.create()) the resulting permission is DENY.

[
   {
      principalType:'ROLE',
      principalId:'$everyone',
      permission:'DENY'
   },
   {
      principalType:'ROLE',
      principalId:'$everyone',
      property:'create',
      permission:'ALLOW'
   }
]

Exception in `GET /models` (from sls-sample-app)

ReferenceError: remotes is not defined
    at Object.handle (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/lib/middleware/rest.js:26:23)
    at next (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
    at Object.expressInit [as handle] (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/lib/middleware.js:31:5)
    at next (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
    at Object.query [as handle] (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/middleware/query.js:44:5)
    at next (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
    at Function.app.handle (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:198:3)
    at Server.app (/Users/schoon/Projects/strongloop/sls-sample-app/node_modules/loopback/node_modules/express/node_modules/connect/lib/connect.js:65:37)
    at Server.EventEmitter.emit (events.js:98:17)
    at HTTPParser.parser.onIncoming (http.js:2027:12)

Undocumented: oauth2

There is no documentation for the oauth2 model although it is present in the current version of loopback.

Also there are no code examples on creating and accessing an oauth2 protected resource.

Simplify the registration of default datasources

At the moment, user has to always specify defaultForType property when registering a default data source. I would like some kind of convention that would pick the default datasource based on the datasource name.

// This will set mail as defaultForType mail
// unless another data source overrides the default
app.dataSource('mail', { connector: 'mail' });

// This is the current usage
app.dataSource('mail', {
 connector: 'mail',
 defaultForType: 'mail'
});

Example of a naive approach that does not work now (the code is from unit-tests):

var loopback = require('loopback');
var app = loopback();

app.dataSource('mail', { connector: 'mail' });
app.dataSource('db', { connector: 'memory' });

loopback.autoAttach();

/cc @ritch @raymondfeng

Related issue: #155.

loopback.createModel must fail when base model was not found

At the moment, loopback.createModel() silently ignores unkown base model and uses loopback.Model instead. See lib/loopback.js#L136.

The problem then surfaces much later and the error message is not helpful.

Example:

var user = app.model('user', {
  options: {
    base: 'User',
    relations: {
       accessTokens: {
         model: 'accessToken',  // should be `AccessToken`
         type: 'hasMany',
         foreignKey: 'userId'
       }
    }
  },
  dataSource: 'db'
});

app.enableAuth();

var credentials = { email: '[email protected]', password: 'password'};
user.create(credentials, function(err) {
  if (err) throw err;
  user.login(credentials, function(err) {
    if (err) throw err;
    console.log('login passed');
  });
});

Result:

/Users/bajtos/src/loopback/loopback/lib/models/user.js:152
          user.accessTokens.create({
                            ^
TypeError: Cannot call method 'create' of undefined
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:152:29
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:202:7
    [etc.]

/cc: @ritch @raymondfeng

API Discussion

The 0.7 api is documented here. This is our last chance to make major changes to the API before moving on to a stable release (v0.8.0).

Just like node: odd releases are unstable. Unstable versions may include major breaking changes.

Stable releases (even, 0.8.x, etc) will not change api and only include bug fixes per release (eg. 0.8.1, 0.8.2, etc).

  • master is at v0.6.0 and is fairly stable
  • refactor/api branch is 0.7.0 unstable
  • 0.8 is our upcoming stable release

Please take a look at the 0.7 api docs and either

  • make a comment here with any suggestions, changes, ideas, etc
  • create a pull request with your change

Data Importing

There are several use cases for importing data into a loopback data source. I've listed the ones that I can think of, feel free to add any.

  1. As a developer working on a new project, I need test data to work with. This could be for integration tests, prototyping, or even modeling data.
  2. As a developer working on an existing project with exsiting data, I need to constantly update my local development data with that which mirrors, closely mirrors, or simulates prodution data.
  3. LoopBack internals require data to be imported during app startup. Although it is important to note that the core could be modified in a way that does not depend on bootstrapped data.

Here is a basic example of an API and JSON format that could make implementing these use cases fairly straightforward and simple.

var app = loopback();
var db = app.dataSource('db', {connector: loopback.Memory});
var Car = app.model('Car', {dataSource: 'db'});
var Dealership = app.model('Dealership', {dataSource: 'db'});
var Option = app.model('Option', {dataSource: 'db'});
var Make = app.model('Make', {dataSource: 'db'});

Dealership.hasMany(Car);
Car.hasMany(Option);
Make.hasMany(Car);

// data.json
{
  data: {
    dealerships: [
      {
        name: 'acme cars',
        $cars: [
          {model: '500', $make: '#fiat', $options: ['#leather', '#ac']},
          {model: 's4', $make: '#audi', $options: '.audi-options'},
          {model: 'm3', $make: '#bmw'},
        ]
      }
    ],
    makes: [
      {name: 'audi', $$id: 'audi'}
      {name: 'fiat', $$id: 'fiat'}
      {name: 'bmw', $$id: 'bmw'}
    ],
    options: [
      {name: 'leather', $$id: 'leather'},
      {name: 'ac', $$id: 'ac'},
      {name: 'audi option 1', $$class: 'audi-options'},
      {name: 'audi option 2', $$class: 'audi-options'}
    ]
  }
}

var testData = app.createDataSet({
  file: 'data.json', //or data: someDataObj
});

testData.import({drop: true}, function (err) {
  console.log(err || 'Data imported');
});

A bit of reference for the JSON format:

  • $$ - indicates a reference only for use by the importer, allowing references / relations to be created before the actual object is inserted and id generated
  • $$id - for referencing a single instance
  • $$class - for referencing several instances
  • $ - indicates a special property. For now, this is used only for relations
  • $myRleationProperty - indicates the value for this key is a string or array of strings referencing classes or ids (see above).
  • .my-class-name - similar to how classes work in CSS: allows you to reference a set of objects tagged with a $$class: 'my-class-name.
  • #my-id - similar to how ids work in CSS: allows you to reference a single object by id

Post to related entity crashes node

I'm not sure which layer of the system this occurs in but, here's how to reproduce it:

  • Create a new application via:slc lb project bug-test
  • Disable authentication (for the test) (comment out line 130, I think)
  • Start the application: npm start or slc start
  • Run: ```
    curl -X POST -H 'Content-Type: application/json' -d '{"email":"[email protected]", "password":"test"}' http://localhost:3000/api/users

curl -X POST -H 'Content-Type: application/json' -d '["anything"]' http://localhost:3000/api/users/1/accessTokens


For me, I get this at the client: ```
{
  "password": "$2a$10$fgKqrtWcxkLcnuYtQ1n9O.68rjEPFQjIaVTcdQZkiOqQgtHKa4s7G",
  "email": "[email protected]",
  "credentials": [],
  "challenges": [],
  "id": 1
}curl: (52) Empty reply from server

and node crashes with:

POST /api/users 200 352ms - 154b

TypeError: Object #<ModelConstructor> has no method 'build'
    at ModelConstructor.create (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback-datasource-juggler/lib/scope.js:132:14)
    at ModelConstructor.fn_create [as __create__accessTokens] (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback-datasource-juggler/lib/scope.js:100:11)
    at SharedMethod.invoke (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:131:17)
    at HttpContext.invoke (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/http-context.js:221:12)
    at /Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:416:9
    at execStack (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:287:7)
    at RemoteObjects.execHooks (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:291:10)
    at RemoteObjects.invokeMethodInContext (/Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:413:8)
    at /Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/async/lib/async.js:548:21
    at /Users/csalch/code/bestfit/surdell/example/bug-test/node_modules/loopback/node_modules/async/lib/async.js:224:13

npm ERR! [email protected] start: `node app.js`
npm ERR! Exit status 8
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is most likely a problem with the bug-test package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node app.js
npm ERR! You can get their info via:
npm ERR!     npm owner ls bug-test
npm ERR! There is likely additional logging output above.
npm ERR! System Darwin 12.5.0
npm ERR! command "/usr/local/Cellar/node/0.10.22/bin/node" "/usr/local/bin/npm" "start"
npm ERR! cwd /Users/csalch/code/bestfit/surdell/example/bug-test
npm ERR! node -v v0.10.22
npm ERR! npm -v 1.3.14
npm ERR! code ELIFECYCLE
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     /Users/csalch/code/bestfit/surdell/example/bug-test/npm-debug.log
npm ERR! not ok code 0

I've tried creating my own related models and see the same result as the above. Any ideas?

latest update fails http://localhost:3000/models when using the oracle database

latest update fails http://localhost:3000/models when using the oracle database

ReferenceError: remotes is not defined
at Object.handle (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/lib/middleware/rest.js:26:23)
at next (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
at Object.expressInit as handle
at next (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
at Object.query as handle
at next (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:190:15)
at Function.app.handle (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/node_modules/express/node_modules/connect/lib/proto.js:198:3)
at Server.app (/Users/mattschmulen/nodelife/strongloop/strongloop-community/loopback-ios-guide-app/loopback-nodejs-server/node_modules/loopback/node_modules/express/node_modules/connect/lib/connect.js:65:37)
at Server.EventEmitter.emit (events.js:98:17)
at HTTPParser.parser.onIncoming (http.js:2056:12)

Unable to disable specific remoteMethods on an individual model/instance

This is a problem with the strong-remoting api. Since all Models share the same actual Function object, setting Model.myFunc.shared = false will set this for all other Models. We probably need to introduce an api and some LDL to handle this specifically.

Node.js

MyModel.disableRemoteMethod('create');

LoopBack Definition Language / JSON

{
  "MyModel": {
    ...
    "remoteMethods": {
      "create": {"disabled": true}
    }
  }
}

/cc @raymondfeng @bajtos

The quest for a better User.login

While implementing client SDKs consuming the new ACL/Auth features, we have found that client apps usually need to get details of the currently logged in user. At the moment, clients have to send two requests: User.login and User.get.

We should modify User.login so that it optionally adds the user data to the response.

Objectives

  1. Backwards compatibility. /users/login should return the same response as before this change.
  2. Opt-in scheme. Clients have to explicitly request the inclusion of user data.

/to @raymondfeng @ritch @Schoonology let's discuss what's the best solution. I'll describe few of them in a comment.

LoopBack models should inherit config.options from the parent

When LB developer wants to access built-in LB models via app.models, he has to define subclasses in models.json. The current implementation requires that a lot of config options of the base model must be repeated in the subclass definition.

This has several disadvantages:

  1. It's difficult to add a built-in model to your app, especially if you are new to loopback.
  2. If we modify the built-in model (e.g. by adding another relation), existing application will break after upgrade.

Below are the use cases I discovered while writing E2E tests for loopback-angular.

datasource

app.model('MyUser', {
  options: { base: 'User' },
  dataSource: 'db'
});

Result:

assert.js:92
  throw new assert.AssertionError({
        ^
AssertionError: MyUser is referencing a dataSource that does not exist: "undefined"
    at modelFromConfig (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/application.js:545:3)
    at Function.app.model (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/application.js:115:38)
    [etc.]

Since the new model is a subclass of a built-in model, it should use the same datasource that was configured for the User model.

If the datasource of the base class was not resolved yet, but it has autoAttach property, then the process of attaching the subclass to a datasource should be deferred to loopback.autoAttach.

relations

var user = app.model('user', {
  options: {
    base: 'User',
  },
  dataSource: 'db'
});

app.enableAuth();

var credentials = { email: '[email protected]', password: 'password'};
user.create(credentials, function(err) {
  if (err) throw err;
  user.login(credentials, function(err) {
    if (err) throw err;
    console.log('login passed');
  });
});

Result:

/Users/bajtos/src/loopback/loopback/lib/models/user.js:152
          user.accessTokens.create({
                            ^
TypeError: Cannot call method 'create' of undefined
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:152:29
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:202:7
    at /Users/bajtos/src/loopback/loopback/node_modules/bcryptjs/bcrypt.min.js:40:101
    [etc]

To fix this problem, one has to re-define User relations:

var user = app.model('user', {
  options: {
    base: 'User',
    relations: {
      accessTokens: {
        model: 'AccessToken',
        type: 'hasMany',
        foreignKey: 'userId'
      }
    }
  },
  dataSource: 'db'
});

v1.6.2 is not backwards compatible with v1.6.1 projects

Steps to reproduce:

  1. Create the following package.json file:

    {
      "dependencies": {
        "loopback-datasource-juggler": "~1.2.13",
        "loopback": "~1.6.0"
      }
    }
  2. Run npm install.

    [cut]
    npm ERR! peerinvalid
      The package loopback-datasource-juggler 
      does not satisfy its siblings' peerDependencies requirements!
    npm ERR! peerinvalid
      Peer [email protected] wants loopback-datasource-juggler@~1.3.0
    

The problem is IMO caused by loopback v1.6.2 breaking semver rules.

How to fix the immediate problem:

  • release loopback v1.6.2 as v1.7.0
  • npm unpublish [email protected]
  • update loopback-workspace to depend on loopback >=1.7, publish a new patch version

/to @raymondfeng @ritch Any objections to taking the two actions above?

Longterm:

When we bump up the version of loopback-datasource-juggler required by loopback to a different major/minor version, we must release this change as a minor version of loopback.

Possibly related: the comment in #85.

Changes made in afterRemote hooks are discarded

Consider the following hook:

User.afterRemote('**', function(ctx, result, next) {
  delete result.password;
  result.newProp = 'new-value';
  result.email = 'modified:' + result.email;
  next();
});

// Result of POST /users
{
  password: '$2a$10$6Ck1zg3NgKLrsRHelaV9MuwwbOFbfxVnSccTcWvODRAC16c85/r0i',
  email: 'modified:[email protected]',
  credentials: [],
  challenges: [],
  id: 1 
}

In other words, password property was not removed, newProp was not added, only the modification of an existing property was applied.

Partial workaround based on the internal details of ModelBaseClass:

user.afterRemote('**', function(ctx, result, next) {
  delete result.__data.password;
  result.__data.newProp = 'new-value';
  result.email = 'modified:' + result.email;
  next();
});

// Result of POST /users
{
  password: null,
  email: 'modified:[email protected]',
  credentials: [],
  challenges: [],
  id: 1,
  newProp: 'new-value'
}

Related and/or affected issues: #160, #161.

/cc @Raymond @Ritchie

support configuration of datasources/models from environment variables and other sources

the current LB datasource configuration makes it awkward to deploy a mongo (mongolab) db based app to Heroku.

LB datasources:

  "mongodb": {
    "defaultForType": "mongodb",
    "connector": "loopback-connector-mongodb",
    "database": "dbname",
    "host": "localhost",
    "port": "27017"
  },

The instructions on Heroku are to use a process.env variable to dynamically assign the url value eg:

var mongoUri = process.env.MONGOLAB_URI ||
  process.env.MONGOHQ_URL ||
  'mongodb://localhost/mydb';

A pseudo work-around is to configure the LB datasource to use the 'url' property instead of database/host/port and then get Heroku to spit out the connection string
https://devcenter.heroku.com/articles/mongolab#getting-your-connection-uri
eg:

$ heroku config | grep MONGOLAB_URI
MONGOLAB_URI => mongodb://heroku_app1234:[email protected]:29017/heroku_app1234

and then reset the datasources.js to this:

  "mongodb": {
    "defaultForType": "mongodb",
    "connector": "loopback-connector-mongodb", 
    "url":"mongodb://heroku_app1234:[email protected]:29017/heroku_app1234"
  },

this kind of works but is a bit awkward. It would be good if I could just plug in my environment vars.

LoopBack app should have a pre-configured email transport

LoopBack app should come with a pre-configured set of datasources to make it easy to boot an application in unit tests. For example, there should be a dummy mail connector that is used when no other connector is defined.

Consider the following code snippet:

var loopback = require('loopback');
var app = loopback();

loopback.autoAttach();

The result is an assertions error:

assert.js:92
  throw new assert.AssertionError({
        ^
AssertionError: cannot autoAttach model "Email". No dataSource found of type mail
    at Function.loopback.autoAttachModel (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/loopback.js:274:5)
    at /Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/loopback.js:265:16
    at Array.forEach (native)
    at Function.loopback.autoAttach (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/loopback.js:260:23)
    at Object.<anonymous> (/Users/bajtos/src/loopback/loopback/bug.js:4:10)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)

While the fix is one line, I find it annoying that my code has to deal with emails when I don't care about them at all. Not to mention that it's not immediately clear what you have to put on that one line.

app.dataSource('mail', { 
  connector: 'mail',
  defaultForType: 'mail'
});

/cc @ritch @raymondfeng

Custom async steps in `app.boot()`

As a developer, I want to write code for setting up my db with pre-defined data and put this code in a file that is automatically picked up and executed by app.boot().

Example:

// {project}/data/static.js
module.exports = function createStaticData(app, cb) {
  User.create(
    { 
      email: '[email protected]',
      role: 'developer'
    },
    cb);
}

ACL definitions in models.json have a field name property that is undocumented ...

When defining ACL's in a models.json file, there is a field property that appears to be critical to the definition of the ACL.

{
  "accessType": "*",
  "permission": "ALLOW",
  "principalType": "ROLE",
  "principalId": "masterAdmin",
  "property":"find" <--------- this one
}

Documentation at http://docs.strongloop.com/display/DOC/Model+definition+reference#Modeldefinitionreference-acls show's that the field exists but does not tell how/when it is used.

API Swagger not including models

I've noticed that the swagger code is not including model schemas for requests. I was pretty sure I'd seen this working at one time, but it doesn't appear to be now. If it wasn't, this would be a very nice to have feature.

Custom/composite identifiers in client SDKs

By default, LoopBack assumes that each model has id property that uniquely identifies every model instance.

However, LDL allows to customise this:

  1. Use different property as the identifier.

    loopback.createModel('Customer', {
      email: { id: true, type: String }
    });
  2. Use a composite id - there is a combination of multiple properties that uniquely identifies every model instance.

    // I am not sure if this is the right syntax,
    // correct me if I am wrong
    loopback.createModel('City', {
    state: { id: true, type: String },
    name: { id: true, type: String }
    });

Even when the identifier is not id, the REST API expects a single id parameter in the URL (e.g. GET /customers/:id), even though the JSON documents in requests/responses contain the custom/composite identifier.

This solution brings extra complexity to LB clients.

To begin with, client models need to decide whether they are representing an existing instance or a new object, so that save can call update or create. The current implementations (Android, iOS) are assuming there is always and id property. When this property is set, then the model is an existing instance.

Arbitrary identifiers makes it difficult for front-end developers to use the REST API. For every model, they have to remember what is the identifier and understand when to send it as customId and when as id.

For ids that are not auto-generated (as is the case of the code samples above), we can't decide between update and create just by checking whether the id property was set.

We need a better solution. Thoughts?

/to: @ritch @Schoonology @raymondfeng

RFC - Push Notification Implementation / API

/cc @bajtos @raymondfeng

Here is a basic example of working with the push notification API (available in master).

What we have now

var ds = require('./data-sources/db');
var PushModel = require('../index')(app, {dataSource: ds});
var Application = PushModel.Application;
var Device = PushModel.Device;

Application.find({
    where: { name: 'LoopBackPushNotificationDemoApplication' }
  },
  function(err, result) {
    if (err) throw err;
    if (result.length > 0) {
      console.log('Application id:', result[0].id); // hack to get the id for use on the client
      return;
    }

    // Register our application
    Application.register(
      'strongloop',
      'LoopBackPushNotificationDemoApplication',
      {
        id: 'loopback-push-notification-app',
        description: 'LoopBack Push Notification Demo Application',
        pushSettings: {
          gcm: {
            pushOptions: {
              serverKey: 'Your-Server-API-Key'
            }
          }
        }
      },
      function(err, app) {
        if (err) throw err;
        console.log('Application id:', app.id);
      }
    );
  }
);

app.post('/devices/:id/notify', function (req, res, next) {
  var note = {
    text: '\uD83D\uDCE7 \u2709 Hello',
    sender: 'gcm loopback app'
  };

  PushModel.pushNotificationByRegistrationId(req.params.id, note);
  res.send(200, 'OK');
});

Here are the issues I see with the current API (referencing the example above):

  1. You have to dynamically create an application object. IMO this is a pretty bad approach. Almost everything depends on this object, and specifically the app's id. This should be available from a config file or statically somehow. It should be reference-able from clients and within node (by a static id perhaps) before it is even created.
  2. It is also difficult to know that a push notification has failed. There isn't even a callback which at least could include potential timeout errors.
  3. The notify API is surfaced as POST /devices/:id/notify. I think this can be improved. We should have a Notification model with a remote-able send method, similar to MyModel.create.

What I think we should move to

var Notification = loopback.Notification;
var Application = loopback.Application;
var Device = loopback.Device;

var androidApp = new Application(
  {
    org: 'strongloop',
    name: 'LoopBackPushNotificationDemoApplication',
    id: 'android-app',
    description: 'LoopBack Push Notification Demo Application',
    pushSettings: {
      gcm: {
        pushOptions: {
          serverKey: 'Your-Server-API-Key'
        }
      }
    }
  }
);

console.log(androidApp.id); // 'android-app'

androidApp.save();

app.model(Notification);
app.model(Device);

// from client over rest
// POST /notifications
// {
//   text: '\uD83D\uDCE7 \u2709 Hello',
//   sender: 'gcm loopback app',
//   deviceId: 'my-device-id'
// }

Ability to define a bulk ALLOW once a wildcard DENY is in place.

The way permissions are presently defined, a wildcard DENY trumps any acl does not exactly match on model, property, and accessType. While this is the technically correct solution, it would be nice to be able to setup a wildcard DENY for $everyone and then do a wildcard ALLOW for other roles.

I know this presents a problem with deciding which acl should have priority as there is currently nothing to assign a weight to roles or the acls themselves. Adding that should make this pretty simple to do.

Support multiple model JSON files

See the StackOverflow question:

I have many models to define, that I don't want to define in a single enormous json file, and hence want to place one js file per model in the said models/ directory to be loaded at boot time.

Post to /api/users/logout crashes node

Steps to reproduce:

  1. Create an application with slc lb project bug-test
  2. Start application with npm start or slc start
  3. Run curl -X 'POST' localhost:3000/api/users/logout

I've seen this happen with and without an access token parameter.

Console output:

csalch@Chriss-MacBook-Air ~/bug-test $ npm start

> [email protected] start /Users/csalch/bug-test
> node app.js

StrongOps not configured to monitor. Please refer to http://docs.strongloop.com/strong-agent for usage.
connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Browse your REST API at http://0.0.0.0:3000/explorer
LoopBack server listening @ http://0.0.0.0:3000/

/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:83
          throw new Error(name + ' is a required arg');
                ^
Error: access_token is a required arg
    at /Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:83:17
    at Array.forEach (native)
    at SharedMethod.invoke (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:74:13)
    at HttpContext.invoke (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/http-context.js:221:12)
    at /Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:416:9
    at execStack (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:287:7)
    at /Users/csalch/bug-test/node_modules/loopback/lib/application.js:177:13
    at /Users/csalch/bug-test/node_modules/loopback/lib/models/acl.js:445:17
    at /Users/csalch/bug-test/node_modules/loopback/lib/models/acl.js:408:19
    at /Users/csalch/bug-test/node_modules/loopback/node_modules/async/lib/async.js:229:13

npm ERR! [email protected] start: `node app.js`
npm ERR! Exit status 8
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is most likely a problem with the bug-test package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node app.js
npm ERR! You can get their info via:
npm ERR!     npm owner ls bug-test
npm ERR! There is likely additional logging output above.
npm ERR! System Darwin 12.5.0
npm ERR! command "/usr/local/Cellar/node/0.10.24/bin/node" "/usr/local/bin/npm" "start"
npm ERR! cwd /Users/csalch/bug-test
npm ERR! node -v v0.10.24
npm ERR! npm -v 1.3.21
npm ERR! code ELIFECYCLE
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     /Users/csalch/bug-test/npm-debug.log
npm ERR! not ok code 0

npm ls

[email protected] /Users/csalch/bug-test
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚   โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚   โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚   โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚   โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ””โ”€โ”ฌ [email protected]
โ”‚ โ”‚   โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚   โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ””โ”€โ”€ [email protected]
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ””โ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”ฌ [email protected]
โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ”‚ โ””โ”€โ”€ [email protected]
โ”‚ โ”œโ”€โ”€ [email protected]
โ”‚ โ””โ”€โ”€ [email protected]
โ””โ”€โ”ฌ [email protected]
  โ”œโ”€โ”ฌ [email protected]
  โ”‚ โ””โ”€โ”€ [email protected]
  โ”œโ”€โ”€ [email protected]
  โ””โ”€โ”ฌ [email protected]
    โ”œโ”€โ”€ [email protected]
    โ”œโ”€โ”€ [email protected]
    โ””โ”€โ”ฌ [email protected]
      โ””โ”€โ”€ [email protected]

How to customize default ACLs

As of #102, the User model includes an opinionated set of of ACLs that allow access where it makes sense for all applications.

Can we describe in the documentation how to customise this default ACL, e.g. allow only admin to create new users?

An automated test demonstrating this behaviour would be even better.

Bugs in User model

Require for 'assert' is missing in built-in user model.
Also when sending email verification email connector is throwing error, seems that transportsIndex is undefined and causing exception. (Property should be set in the setupTransport method).

Users are created and authenticated in memory instead of oracle db

I have set up the user auth tokens and Angular services file to facilitate user registration and authentication but it seems to be working against the memory db instead of my oracle db.

I double checked and my User model is pointed at my oracleDB datasource.

My accessToken model was originally pointing to the memory 'db' datasource but I changed it to oracleDB but it doesn't seem to have made a difference.

When I run my app I am able to create new users and then I am also then able to log in with those users but if I restart my server the users are lost and I am unable to login.

I get the following error:

"Error: login failed
    at /Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback/lib/models/user.js:142:24
    at /Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback-datasource-juggler/lib/dao.js:590:66
    at /Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback-datasource-juggler/lib/dao.js:559:13
    at /Users/seanbrookes/_stacks/projects/bacn-icar/server/node_modules/loopback-datasource-juggler/lib/connectors/memory.js:195:13
    at process._tickDomainCallback (node.js:459:13)"

Using Node Inspector I was expecting the Model.prorotype.save method to be called in dao.js (loopback-datasource-juggler.js line: 690) but it doesn't seem to execute that code during registration.

Configurable logger format

Add a new app config option for setting the format string used by loopback.logger middleware.

Use the values from loopback-workspace as the default:

app.use(loopback.logger(
  this.get('env') === 'development' ? 'dev' : 'default'));

`app.model` should report unknown options

Consider the following code:

var User = app.model('User', {
  options: { base: 'User' },
  relations: {
    accessTokens: {
      model: "AccessToken",
      type: "hasMany",
      foreignKey: "userId"
    }
  },
  dataSource: 'Memory'
});

LoopBack happily ignores relations property and creates a User model without relations. The problem manifests with a mysterious crash of the application much later:

server/node_modules/loopback/lib/models/user.js:160
          user.accessTokens.create({
                            ^
TypeError: Cannot call method 'create' of undefined
    at server/node_modules/loopback/lib/models/user.js:160:29
    at server/node_modules/loopback/lib/models/user.js:224:7
    at server/node_modules/loopback/node_modules/bcryptjs/bcrypt.min.js:40:101
    [cut]

Proposal

app.model and app.dataSource should throw an error when the configuration contains unknown properties.

A better way how to include `belongsTo` model in response

A follow-up for #161, where we modified User.login to fill accessToken.__data.user with the current user.

Once #162 is fixed, it may be tempting to change that line to accessToken.user. However, there is a caveat.

Because AccessToken belongsTo User, it already has a user property of type function (see loopback-datasource-juggle/lib/relations.js#L244).

If User.login overrides this property value then the code calling User.login directly may stop working.

User.login(credentials, function(err, token) {
  token.user(function(err, user) {
    // do something
  });
});

I feel there should be a better way for exposing the belongsTo models in the JSON response, possibly similar to the solution in loopbackio/loopback-datasource-juggler#64. @raymondfeng could you advise?

User.login fails with "Cannot call method 'create' of undefined"

Run the following LoopBack application to reproduce the problem:

var loopback = require('./');
var request = require('supertest');
var app = loopback();

var db = loopback.createDataSource({ connector: 'memory' });

loopback.User.attachTo(db);
app.model(loopback.User);
loopback.AccessToken.attachTo(db);
loopback.User.hasMany(loopback.AccessToken);

app.enableAuth();
app.use(loopback.token());
app.use(loopback.rest());

var credentials = { email: '[email protected]', password: 'password'};
loopback.User.create(credentials, function(err) {
  if (err) throw err;
  loopback.User.login(credentials, function(err, token) {
    if (err) throw err;
    console.log('passed');
    process.exit();
  });
});

Workaround: create a sub-class of the User model via app.model:

loopback.AccessToken.attachTo(db);
loopback.Role.attachTo(db);
loopback.ACL.attachTo(db);

app.model('User', {
  options: {
    base: 'User',
    relations: {
      accessTokens: {
        model: "AccessToken",
        type: "hasMany",
        foreignKey: "userId"
      }
    }
  },
  dataSource: 'db'
});

app.enableAuth();
// etc.

`app.enableAuth` should fail when models are not configured correctly

The access control code requires that the following models are present & attached to a datasource:

loopback.User
loopback.AccessToken
loopback.Role
loopback.ACL

Additionally User model must have a hasMany relationship with AccessToken.

Expected behaviour
app.enableAuth() should check that these models are correctly configured, otherwise throw an error.

It would be nice if the pre-build User and AccessToken models have the relationship already defined.

Notes
It's possible the list is not complete, how about RoleMapping or Scope?

Bring in automated tests from other repositories

At the moment, there are some tests living in this repository (mostly unit-tests?) while other tests (e.g. end-to-end tests for ACL) live in a different repository.

See the discussion in /pull/97

We should really start writing automated tests for these changes and have these tests in the same repository.

Agreed 100%. There are tests for this change. The issue is that they are in a separate repo. I think we need to move all those tests into this repo. If anyone has recommendations on how to structure that, LMK.

https://github.com/strongloop/loopback-example-access-control/blob/master/server/test/access-control.test.js

Measure Performance of ACL checks

Measure how much overhead is added by performing ACL checks. Identify the places that have the worst performance and create follow-up user stories / issues to address the problems found.

See also:

500 error: Angular template GET requests treated as API calls

After updating to ver 1.5.3 I can't seem to load my Angularjs html templates.

These were previously loading fine using ver 1.4.1 via Angular module initialization.
The files live in the /client/www/ directory which is configured in app.js to be a static folder

When I try to load a page in my app I see a series of 500 errors in my console:

Error: ORA-00942: table or view does not exist

GET /modules/dealer/templates/dealerdetail.html 500 488ms
Error: ORA-00942: table or view does not exist

GET /modules/dealer/templates/dealer.main.html 500 737ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/address.lookup.html 500 971ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/location.directive.template.html 500 972ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/find.me.html 500 1459ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/current.location.html 500 1696ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/location.history.html 500 1448ms
Error: ORA-00942: table or view does not exist

GET /modules/location/templates/map.view.html 500 1203ms
Error: ORA-00942: table or view does not exist

GET /modules/search/templates/search.directive.template.html 500 1448ms
Error: ORA-00942: table or view does not exist

GET /modules/profile/templates/profile.main.html 500 1698ms
Error: ORA-00942: table or view does not exist

GET /modules/home/templates/home.template.html 500 1455ms
Error: ORA-00942: table or view does not exist

GET /modules/home/templates/home.app.template.html 500 1219ms

Email.send is not a shared method

It might be useful to use the email model over rest. Setting public: true in models.json should be all that is required to use the email model over REST.

That should (in theory) only take setting the send method as shared.

REST: User response includes hashed password

When a new user is created via User.create, the JSON response contains hashed passwords. In other words, the REST API is leaking potentially sensitive data.

We should come up with a generic solution that will make it easy for LB developers to exclude certain model properties from public responses.

Invalid requests should respond with more detailed info

@raymondfeng @Schoonology @bajtos

Currently we have poor support for responding with validation errors. Below is an overview of what we have and what I think we should move to. Any suggestions would be helpful before making any changes. This might require changes in the iOS SDK, strong-remoting, and the datasource juggler.

  • Using a simple Todo model (ex 1).
  • Making an HTTP request to create a model (ex 2)
  • Current response (ex 3)
  • Potential / Improved response (ex 4)

ex 1

app.model(
  loopback
    .memory()
    .createModel('todo', {
      task: 'string',
      done: 'boolean',
      owner: {type: 'string', required: true}
    })
)

ex 2

POST /todos HTTP/1.1
Content-Type: application/json

{
  "task": "testing...",
  "done": false
}

ex 3

HTTP/1.1 400 Bad Request

ex 4

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "errors": {
    "owner": ["owner is required"]
  }
}

Docs TOC

After a brief discussion @altsang @raymondfeng and I came up with some changes to the docs TOC.

  • LoopBack introduction: get rid of the two question sub headers
  • Concepts should be nouns instead of questions
  • Each concept needs to be explained briefly
    • If there is a related guide (such as for LDL, DataSource, etc) it should be linked to
  • We need an additional concept that describes client centric development
    • This should clearly explain how you develop our app with SDKs like iOS

/cc @Schoonology

Transaction Support

/to @raymondfeng @altsang
/cc @bajtos

In the interest of LoopBack reliability, I'd like to start a discussion on making LoopBack ACID compliant. After brushing off earlier attempts to look into the issue I had an idea.

I think Transactions + Multiversioning will get us 80% or more to ACID.

Transactions

function Transaction(dataSource) {
  this.domain = domain.create();
  this.dataSource = dataSource;
  this.id = this.getHashCode();
  this.snapshots = [];

  domain.transaction = this;
  domain.on('error', this.onError.bind(this));
}

Transaction.prototype.commit = function(callback) {
  this.domain.run(function run() {
    this.dataSource.startTransaction(this);
  }.bind(this));
}

Transaction.prototype.snapshot = function(name, callback) {
  this.snapshots.push(this.dataSource.snapshot(name, this, callback));
}

Transaction.prototype.rollback = function(name, fn) {
  this.currentSnapshot = name ? this.getSnapshot(name) : this.snapshots.pop();
  if(this.currentSnapshot) {
    this.dataSource.applySnapshot(this.currentSnapshot)
  }
}

Transaction.prototype.onError = function() {
  this.rollback(function rollback(err) {
    this.dispose();
    throw err;

  }.bind(this));
}

Transaction.prototype.dispose = function(callback) {
  this.domain.dispose();
  this.dataSource.endTransaction(this, callback);
}

Transaction.getCurrent = function() {
  return domain.active.transaction;
}

// strong-remoting hooking
remotes.before('**', function(ctx, next, method) {
  var t = ctx.transaction = new Transaction(method.constructor.dataSource);
  t.domain.add(ctx.req);
  t.domain.add(ctx.res);
  t.commit(next);
});

remotes.after('**', function(ctx, next) {
  ctx.transaction.dispose(next);
});

The above requires the dataSource / connector to implement methods that delegate to driver transactions, or multiversioning. To support multiversioning, an outer wrapper of the connector could be devised that essentially tracks each method call and model instance. As well as changing the behavior slightly.

Multiversioning

By default all update operations during a transaction would create copies of the given model instance and tag them with the transaction.id. Model's created during the transaction would also be tagged with the transaction.id.

By default, all queries would exlclude instances tagged with transaction.ids.

Failure / Cleanup

If the transaction fails. All models tagged with a transaction.id are removed. This could also be ensured on startup / by a job of some sort to essentially garbage collect tagged instances.

If the transaction completes without error all tagged model instances would replace matching untagged models.

Concerns
During the final phase of a succesful transaction, since transactions aren't isolated by locking, there is a potential for cleanup to happen out of order. If the transaction.id is sortable we might be able to avoid this.

ViewModels

ViewModels

We should support some form of ViewModel. A very simple implementation could depend explicitly on MongoDB. I'm struggling to come up with the exact js API, but the features would be:

  • readonly
  • aggregate data from multiple data sources based on model relations
  • focus on read performance (and local caching config?)
  • able to be created without DBAs / sql / etc
  • avoid joins and slow SQL operations
  • query the aggregated data

A real use case for this is illustrated in the access control example app. The client currently makes a single http request and the server calculates the account balance on demand.

With a ViewModel, the app would make the request to the ViewModel which would be backed by an aggregation (including caluclations) of all the transaction data.

Expose ACL/Roles as REST APIs in models.json

We're building a system where we need to establish custom Roles that will be backed by database object. We're wanting to manage the Roles and RoleMappings via the REST api and ran into troubles getting the models exposed. Our initial attempts involved subclassing the models as has been done with the User object, but we couldn't get this to work right (the exposed model pointed at a collection named role which is different than a collection named Role in Mongo).

In the interim, I've added a couple of app.model lines in our app.js file to expose the needed models. It would be really nice to have this kind of exposure function via the models.json file.

Failed Login Attempt Response is 500 Error

Shouldn't this be something in the 400 series (i.e. bad request?) rather than a 500 (Internal Server Error?)

csalch@Chriss-MacBook-Air ~/bug-test $ curl -X POST -d '{"email":"garbage", "password":"bad" }' http://localhost:3000/api/users/login
{
  "error": {
    "name": "Error",
    "status": 500,
    "message": "must provide username or email",
    "stack": "Error: must provide username or email\n    at Function.User.login (/Users/csalch/bug-test/node_modules/loopback/lib/models/user.js:138:15)\n    at SharedMethod.invoke (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/shared-method.js:131:17)\n    at HttpContext.invoke (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/http-context.js:221:12)\n    at /Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:416:9\n    at execStack (/Users/csalch/bug-test/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:287:7)\n    at /Users/csalch/bug-test/node_modules/loopback/lib/application.js:177:13\n    at /Users/csalch/bug-test/node_modules/loopback/lib/models/acl.js:445:17\n    at /Users/csalch/bug-test/node_modules/loopback/lib/models/acl.js:408:19\n    at /Users/csalch/bug-test/node_modules/loopback/node_modules/async/lib/async.js:229:13\n    at /Users/csalch/bug-test/node_modules/loopback/node_modules/async/lib/async.js:116:25"
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.