Fast, flexible API framework
Make a simple Single Page App, with a front and a API.
I want to follow these 3 basics steps :
I want the first step to be done very fast
Loopback
Each model is connected to a datasource
Missing a connector ? You can still develop your own.
Model
PersistedModel
Access token
ACL
Application
Installation
Push Notification
Relation
Role
User
This model provide following features to any child model.
User extend PersistedModel and add the following features :
// common/models/<model>.json
{
// ...
"acls": [
{
"permission": "ALLOW",
"principalType": "ROLE",
"principalId": "$everyone",
"property": "myMethod"
},
...
]
}
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.
(Users can only access/see discussions they are member of.)
> slc loopback:datasource
// server/datasources.json
{
"db": {
"name": "db",
"connector": "memory"
},
"mongodb": {
"name": "mongodb",
"database": "loopback_test_dev",
"password": "",
"connector": "mongodb",
"user": ""
}
}
> 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": []
}
> slc loopback:relation
// common/models/message.json
{
"name": "Message",
// ...
"properties": {
// ...
},
"validations": [],
"relations": {
"user": {
"type": "hasOne",
"model": "User",
"foreignKey": "userID"
}
},
"acls": [],
"methods": []
}
> slc loopback:acl
Users can only access/see discussions they are member of
// 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": []
}
// 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
});
});
});
};
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.
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"]
}
}
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);
}
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.
@wittydeveloper