Loopback
Fast, flexible API framework
Chat app
Make a simple Single Page App, with a front and a API.
I want to follow these 3 basics steps :
- Implement a basic front with a basic CRUD API
- Add Google sign-in with email blacklist (private beta)
- Be able to make improvements without big refactoring
I want the first step to be done very fast
Which frameworks use ?
- For a front
- Angular, Ember or React allow fast prototyping
- Bootstrap, Material Design allow fast proto too
- For hosting
- AWS, Openshift, Heroku
- An API Server, with a Database
- Firebase, Rails, Parse, MEAN stack ?
Problem
-
Firebase
- No advanced OAuth sign-in configuration
- Rails app
-
rails-api/rails-api
- lack of generators, features
- ACL ?
-
rails-api/rails-api
-
Parse
- self-hosted, lack of NPM modules support
-
MEAN stack
- DIY, lot of work
- even with NPM modules
- Node.js
- Express based
- Fast prototyping
- Performance
- Well documented
Loopback
Tools
Generators
- Application generator : slc loopback.
- Model generator: slc loopback:model.
- Property generator: slc loopback:property.
- Data sources generator: slc loopback:datasource.
- Relationship generator: slc loopback:relation.
- ACL generator: slc loopback:acl.
API explorer
API Composer
Other stuff
- Monitoring
- Cluster mode
- Database discovery
- from schema
- from data
- Swagger generator
- create model from definition
Features
Models
Each model is connected to a datasource
Built-in connectors
- Memory
- MongoDB
- MySQL
- Oracle
- PostgreSQL
- SQL Server
- Email Connector
- Push Connector
- REST Connector
- SOAP Connector
- Storage Connector
Missing a connector ? You can still develop your own.
Built-in models
-
Model
-
PersistedModel
-
Access token
-
ACL
-
Application
-
Installation
-
Push Notification
-
Relation
-
Role
-
User
PersistedModel
This model provide following features to any child model.
User
User extend PersistedModel and add the following features :
ACL
Concepts
-
Principal: An entity that can be identified or authenticated.
-
Role: A group of principals with the same permissions.
- RoleMapping: Assign principals to roles
ACL
// common/models/<model>.json
{
// ...
"acls": [
{
"permission": "ALLOW",
"principalType": "ROLE",
"principalId": "$everyone",
"property": "myMethod"
},
...
]
}
ACL
Components
-
Push Notifications: Adds push notification capabilities to your LoopBack application.
-
Storage service: Adds an interface to abstract storage providers like S3, filesystem into general containers and files.
-
Third-party login: Adds third party login capabilities to your LoopBack application like Facebook, GitHub, etc.
- Synchronization: Adds replication capability between LoopBack running in a browser or between LoopBack back-end instances to enable offline synchronization and server-to-server data synchronization.
Let's make this app
Features
-
Google Sign-in
-
Private beta: email whitelist
-
-
Users can create discussion and invite other users
-
Users can only see/access discussions their are member of.
Models
(Users can only access/see discussions they are member of.)
Scaffold our application
Create a datasource config
> slc loopback:datasource
// server/datasources.json
{
"db": {
"name": "db",
"connector": "memory"
},
"mongodb": {
"name": "mongodb",
"database": "loopback_test_dev",
"password": "",
"connector": "mongodb",
"user": ""
}
}
Create models
> slc loopback:model
// common/models/discussion.json
{
"name": "Discussion",
"plural": "Discussions",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"title": {
"type": "string",
"required": true
},
"open": {
"type": "boolean",
"default": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
// common/models/message.json
{
"name": "Message",
"plural": "Messages",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"content": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
Create models relations
> slc loopback:relation
// common/models/message.json
{
"name": "Message",
// ...
"properties": {
// ...
},
"validations": [],
"relations": {
"user": {
"type": "hasOne",
"model": "User",
"foreignKey": "userID"
}
},
"acls": [],
"methods": []
}
Create models ACL
> slc loopback:acl
Users can only access/see discussions they are member of
- Deny all operations on Discussion model
- Allow all operations on all methods for "memberOf" Role
- Allow create method for all authenticated users
Create models ACL
// common/models/discussion.json
{
"name": "Discussion",
// ...
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "memberOf",
"permission": "ALLOW"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW",
"property": "create"
}
],
"methods": []
}
Create models ACL
// server/boot/script.js
module.exports = function(app) {
var Role = app.models.Role;
Role.registerResolver('memberOf', function(role, context, cb) {
function reject(err) {
if(err) {
return cb(err);
}
cb(null, false);
}
if (context.modelName !== 'discussion') {
// the target model is not discussion
return reject();
}
var userId = context.accessToken.userId;
if (!userId) {
return reject(); // do not allow anonymous users
}
context.model.findById(context.modelId, function(err, discussion) {
if(err || !discussion) {
reject(err);
}
var DiscussionMembers = app.models.DiscussionMembers;
DiscussionMembers.count({
discussionId: discussion.id,
userId: userId
}, function(err, count) {
if (err) {
return reject(err);
}
cb(null, count > 0); // true = is a team member
});
});
});
};
Google Sign-in
Using loopback-component-passport
-
UserIdentity model: keeps track of third-party login profiles.
-
UserCredential model: stores credentials from a third-party provider to represent users’ permissions and authorizations.
-
ApplicationCredential model: stores credentials associated with a client application.
-
PassportConfigurator: the bridge between LoopBack and Passport.
Google Sign-in
Using loopback-component-passport
// server/providers.json
{
"google-login": {
"provider": "google",
"module": "passport-google-oauth",
"strategy": "OAuth2Strategy",
"clientID": "<clientID>",
"clientSecret": "<clientSecret>",
"callbackURL": "<callbackURL>",
"authPath": "/auth/google",
"callbackPath": "/auth/google/callback",
"successRedirect": "/auth/account",
"scope": ["email", "profile"]
}
}
Google Sign-in
Using loopback-component-passport
// server/server.js
var loopback = require('loopback');
var path = require('path');
var app = module.exports = loopback();
// Create an instance of PassportConfigurator with the app instance
var PassportConfigurator = require('loopback-component-passport').PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);
app.boot(__dirname);
...
// Enable http session
app.use(loopback.session({ secret: 'keyboard cat' }));
// Load the provider configurations
var config = {};
try {
config = require('./providers.json');
} catch(err) {
console.error('Please configure your passport strategy in `providers.json`.');
console.error('Copy `providers.json.template` to `providers.json` and replace the clientID/clientSecret values with your own.');
process.exit(1);
}
// Initialize passport
passportConfigurator.init();
// Set up related models
passportConfigurator.setupModels({
userModel: app.models.user,
userIdentityModel: app.models.userIdentity,
userCredentialModel: app.models.userCredential
});
// Configure passport strategies for third party auth providers
for(var s in config) {
var c = config[s];
c.session = c.session !== false;
passportConfigurator.configureProvider(s, c);
}
Loopback is backed by StrongLoop
According to GitHub, StrongLoop [...] made over 420 commits comprising a total contribution of almost 630,000 lines of code to the upcoming v0.12 [node.js] release. These contributions made StrongLoop the largest individual and corporate contributor to v0.12.
Questions ?
@wittydeveloper
Loopback
By Charly Poly
Loopback
Loopback node.js framework presentation
- 3,509