Add initial browser connector example
This commit is contained in:
parent
8ec7b712e8
commit
60d155353a
|
@ -81,7 +81,8 @@ module.exports = function(grunt) {
|
|||
'dist/loopback.js': ['index.js'],
|
||||
},
|
||||
options: {
|
||||
ignore: ['nodemailer', 'passport']
|
||||
ignore: ['nodemailer', 'passport'],
|
||||
standalone: 'loopback'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
|||
// client app
|
||||
var app = loopback();
|
||||
|
||||
app.dataSource('api', {
|
||||
connector: loopback.Server,
|
||||
host: 'localhost',
|
||||
port: 3000,
|
||||
base: '/api',
|
||||
discover: loopback.remoteModels
|
||||
});
|
||||
|
||||
app.dataSource('local', {
|
||||
connector: loopback.Memory
|
||||
});
|
||||
|
||||
var Color = loopback.getModel('Color');
|
||||
var LocalColor = app.model('LocalColor', {dataSource: 'local'});
|
||||
|
||||
LocalColor.create([
|
||||
{name: 'red'},
|
||||
{name: 'green'},
|
||||
{name: 'blue'}
|
||||
], function() {
|
||||
LocalColor.replicate(0, Color, {}, function() {
|
||||
console.log(arguments);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Color.create([
|
||||
// {name: 'red'},
|
||||
// {name: 'green'},
|
||||
// {name: 'blue'}
|
||||
// ], function() {
|
||||
// Color.find(function(err, colors) {
|
||||
// console.log(colors);
|
||||
// });
|
||||
// });
|
||||
|
||||
// Color.find({where: {name: 'green'}}, function(err, colors) {
|
||||
// console.log(colors);
|
||||
// });
|
|
@ -0,0 +1,13 @@
|
|||
<!doctype html>
|
||||
<html lang="en" ng-app="myApp">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>My AngularJS App</title>
|
||||
<link rel="stylesheet" href="css/app.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script src="loopback.js"></script>
|
||||
<script src="loopback-remote-models.js"></script>
|
||||
<script src="client.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +1,20 @@
|
|||
var loopback = require('../../');
|
||||
var app = loopback();
|
||||
var path = require('path');
|
||||
|
||||
app.use(loopback.bundle());
|
||||
app.use(loopback.static(path.join(__dirname, '..', '..', 'dist')));
|
||||
app.use(loopback.static(path.join(__dirname)));
|
||||
app.get('/loopback-remote-models.js', loopback.routes(app));
|
||||
app.use(loopback.rest());
|
||||
|
||||
app.dataSource('db', {
|
||||
connector: loopback.Memory
|
||||
});
|
||||
|
||||
var Color = app.model('Color', {dataSource: 'db', options: {
|
||||
trackChanges: true
|
||||
}});
|
||||
|
||||
app.model(Color.getChangeModel());
|
||||
|
||||
app.listen(3000);
|
||||
|
|
1
index.js
1
index.js
|
@ -12,6 +12,7 @@ var datasourceJuggler = require('loopback-datasource-juggler');
|
|||
loopback.Connector = require('./lib/connectors/base-connector');
|
||||
loopback.Memory = require('./lib/connectors/memory');
|
||||
loopback.Mail = require('./lib/connectors/mail');
|
||||
loopback.Server = require('./lib/connectors/server');
|
||||
|
||||
/**
|
||||
* Types
|
||||
|
|
|
@ -36,4 +36,4 @@ inherits(Memory, Connector);
|
|||
* JugglingDB Compatibility
|
||||
*/
|
||||
|
||||
Memory.initialize = JdbMemory.initialize;
|
||||
Memory.initialize = JdbMemory.initialize;
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/*!
|
||||
* Dependencies.
|
||||
*/
|
||||
|
||||
var assert = require('assert')
|
||||
, loopback = require('../loopback')
|
||||
, debug = require('debug')
|
||||
, path = require('path');
|
||||
|
||||
/*!
|
||||
* Export the ServerConnector class.
|
||||
*/
|
||||
|
||||
module.exports = ServerConnector;
|
||||
|
||||
/*!
|
||||
* Create an instance of the connector with the given `settings`.
|
||||
*/
|
||||
|
||||
function ServerConnector(settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
ServerConnector.initialize = function(dataSource, callback) {
|
||||
var connector = dataSource.connector = new ServerConnector(dataSource.settings);
|
||||
connector.dataSource = dataSource;
|
||||
dataSource.DataAccessObject = function() {}; // unused for this connector
|
||||
var remoteModels = connector.settings.discover;
|
||||
if(remoteModels) {
|
||||
remoteModels.forEach(connector.buildModel.bind(connector));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
ServerConnector.prototype.invoke = function(ctx, callback) {
|
||||
var req = ctx.toRequest();
|
||||
console.log(req);
|
||||
}
|
||||
|
||||
ServerConnector.prototype.createRequest = function(method, args) {
|
||||
var baseUrl = path.join(this.settings.base || '/');
|
||||
var route = (method.routes && method.routes[0]) || {path: '/'};
|
||||
var url = path.join(baseUrl, route.path);
|
||||
}
|
||||
|
||||
ServerConnector.prototype.buildModel = function(remoteModel) {
|
||||
var modelName = remoteModel.modelName;
|
||||
var dataSource = this.dataSource;
|
||||
var connector = this;
|
||||
|
||||
var Model = loopback.createModel(
|
||||
modelName,
|
||||
remoteModel.properties || {},
|
||||
remoteModel.settings
|
||||
);
|
||||
|
||||
Model.attachTo(dataSource);
|
||||
|
||||
if(!Model.defineMethod) {
|
||||
Model.defineMethod = function defineMethod(method) {
|
||||
var scope = method.fullName.indexOf('.prototype.') > -1
|
||||
? Model.prototype : Model;
|
||||
|
||||
scope[method.name] = function() {
|
||||
console.log(method.name);
|
||||
var callback = arguments[arguments.length - 1];
|
||||
var ctx = new Context(
|
||||
connector.settings.base,
|
||||
remoteModel,
|
||||
Model,
|
||||
method,
|
||||
arguments
|
||||
);
|
||||
if(typeof callback !== 'function') callback = undefined;
|
||||
connector.invoke(ctx, callback);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
remoteModel.methods.forEach(Model.defineMethod.bind(Model));
|
||||
}
|
||||
|
||||
function Context(base, meta, model, method, args) {
|
||||
this.base = base;
|
||||
this.meta = meta;
|
||||
this.model = model;
|
||||
this.method = method;
|
||||
this.args = this.mapArgs(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an http request object from the `context`.
|
||||
* @return {Object} request
|
||||
*/
|
||||
|
||||
Context.prototype.toRequest = function() {
|
||||
return {
|
||||
url: this.url(),
|
||||
query: this.query(),
|
||||
method: this.verb(),
|
||||
body: this.body(),
|
||||
headers: this.headers()
|
||||
}
|
||||
}
|
||||
|
||||
Context.prototype.url = function() {
|
||||
var url = path.join(
|
||||
this.base,
|
||||
this.meta.baseRoute.path,
|
||||
this.route().path
|
||||
);
|
||||
|
||||
// replace url fragments with url params
|
||||
return url;
|
||||
}
|
||||
|
||||
Context.prototype.query = function() {
|
||||
var accepts = this.method.accepts;
|
||||
var queryParams;
|
||||
var ctx = this;
|
||||
|
||||
if(accepts && accepts.length) {
|
||||
accepts.forEach(function(param) {
|
||||
var http = param.http || {};
|
||||
var explicit = http.source === 'query';
|
||||
var implicit = http.source !== 'body' && http.source !== 'url';
|
||||
|
||||
if(explicit || implicit) {
|
||||
queryParams = queryParams || {};
|
||||
queryParams[param.arg] = ctx.args[param.arg];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return queryParams;
|
||||
}
|
||||
|
||||
Context.prototype.route = function() {
|
||||
var routes = this.method.routes;
|
||||
|
||||
return routes[0] || {path: '/', verb: 'GET'};
|
||||
}
|
||||
|
||||
Context.prototype.verb = function() {
|
||||
return this.route().verb.toUpperCase();
|
||||
}
|
||||
|
||||
Context.prototype.body = function() {
|
||||
var accepts = this.method.accepts;
|
||||
var body;
|
||||
var ctx = this;
|
||||
|
||||
if(accepts && accepts.length) {
|
||||
accepts.forEach(function(param) {
|
||||
var http = param.http || {};
|
||||
var explicit = http.source === 'body';
|
||||
|
||||
if(explicit) {
|
||||
body = ctx.args[param.arg];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
Context.prototype.headers = function() {
|
||||
return {};
|
||||
}
|
||||
|
||||
Context.prototype.mapArgs = function(args) {
|
||||
var accepts = this.method.accepts || [];
|
||||
var args = Array.prototype.slice.call(args);
|
||||
var result = {};
|
||||
var supportedSources = ['body', 'form', 'query', 'path'];
|
||||
|
||||
accepts.forEach(function(param) {
|
||||
if(param.http && param.http.source) {
|
||||
// skip explicit unknown sources
|
||||
if(supportedSources.indexOf(param.http.source) === -1) return;
|
||||
}
|
||||
|
||||
var val = args.shift();
|
||||
var type = typeof val;
|
||||
if(Array.isArray(val)) {
|
||||
type = 'array';
|
||||
}
|
||||
|
||||
// skip all functions
|
||||
if(type === 'function') return;
|
||||
|
||||
switch(param.type) {
|
||||
case 'any':
|
||||
case type:
|
||||
result[param.arg] = val;
|
||||
break;
|
||||
default:
|
||||
// skip this param
|
||||
args.unshift(val);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*!
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var loopback = require('../loopback');
|
||||
|
||||
/**
|
||||
* Export the middleware.
|
||||
*/
|
||||
|
||||
module.exports = models;
|
||||
|
||||
/**
|
||||
* Return a script that defines all remote models.
|
||||
*/
|
||||
|
||||
function models(app) {
|
||||
return function (req, res, next) {
|
||||
var script = 'window.loopback.remoteModels = ';
|
||||
var models = [];
|
||||
app.handler('rest').adapter.getClasses().forEach(function(c) {
|
||||
if (!c.ctor) {
|
||||
// Skip classes that don't have a shared ctor
|
||||
// as they are not LoopBack models
|
||||
console.error('Skipping %j as it is not a LoopBack model', name);
|
||||
return;
|
||||
}
|
||||
models.push(toJSON(c));
|
||||
});
|
||||
res.send(script + JSON.stringify(models, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
function toJSON(sharedClass) {
|
||||
var model = loopback.getModel(sharedClass.name);
|
||||
|
||||
return {
|
||||
modelName: model.modelName,
|
||||
settings: model.settings,
|
||||
properties: model.properties,
|
||||
baseRoute: sharedClass.routes[0],
|
||||
methods: sharedClass.methods
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue