LoopBack:如何在代码中动态创建自定义 REST 端点(动态)
LoopBack: How to Dynamically Create Custom REST Endpoints In Code (On The Fly)
我们正在使用 LoopBack REST 框架来公开我们的数据库(和业务逻辑)。我们需要允许我们的客户在数据库(单租户和多租户)中创建可以通过 REST 端点访问的自定义表。所有客户都需要使用相同的公共(生产)REST 端点,这些端点将暴露在多台服务器上。但是,自定义表和关联的 REST 端点需要仅供创建它们的客户访问。这意味着我们无法将自定义表的模型写入光盘。我们需要能够在我们的生产 REST 端点的上下文中动态创建一个实际的 REST 端点。
问题:我们如何在不将模型写入光盘上的 JSON 文件的情况下,在代码中动态创建自定义 REST 端点(动态)?
您可以在模型的 JS 文件中创建一个 "remote method",这会添加 API 挂钩 "at runtime",尽管它是在启动时。也就是说,我认为您可以随时使用相同的函数来添加端点,而不仅仅是在启动时(尽管我从未尝试过):
里面/common/models/MyModel.js
module.exports = function(MyModel){
// This is the endpoint for creating endpoints...
MyModel.addEndpoint = function(name, method, cb) {
// audit name and method...
MyModel[name] = function(options, newCb) {
// do whatever this endpoint should do...
newCb(null, 'New endpoint success!');
};
MyModel.remoteMethod(
name,
{
accepts: [{arg: 'options', type: 'object'}], // or whatever you need...
returns: {arg: 'message', type: 'string'}, // whatever it returns...
http: {verb: method}
}
);
cb(null, 'Success creating new endpoint!');
};
MyModel.remoteMethod(
'addEndpoint',
{
accepts: [
{arg: 'name', type: 'string', http: {source: 'body'}},
{arg: 'method', type: 'string', http: {source: 'body'}}
],
returns: {arg: 'message', type: 'string'},
http: {verb: 'post'}
}
);
};
我在环回中也遇到过类似的问题。
我想出的解决方案是:
在我的数据库中维护一个 table [id INT, modelName VARCHAR, datasource VARCHAR, modelConfig TEXT],它可以保存任何其他 table 的模型定义。
在环回中创建一个模型(称之为 X)以提供对此 table 的 CRUD 操作。
在 X 中创建 remoteMethod 以更新应用程序对象中的模型并附加到任何数据源。
实现片段如下:
X.updateModel = (modelName, cb) => {
let app = X.app;
if (modelName) {
X.find({
where: {
name: modelName
}
}, function(err, result) {
result.forEach(row => {
let {
datasource,
modelConfig
} = row;
// Create a new model
createAndAttachModel(app, datasource, JSON.parse(modelConfig));
});
});
cb(null, "Created :" + modelName);
}
};
X.remoteMethod('updateModel', {
accepts: {arg: 'name', type: 'string'},
returns: {arg: 'result', type: 'string'},
http: {verb: 'get'},
});
let createAndAttachModel = (app, datasource, model) => {
var loopback = require("loopback");
try {
// Create a new model object using the model incoming from the database
let newModel = loopback.createModel(model);
// Attach the model to an existing datasource
app.model(newModel, {
dataSource: null,
public: true
});
let currDataSource = app.datasources[datasource];
if (currDataSource) {
newModel.attachTo(currDataSource);
} else {
console.error(datasource, "is not initialized");
}
} catch (error) {
console.error(error);
}
};
我们正在使用 LoopBack REST 框架来公开我们的数据库(和业务逻辑)。我们需要允许我们的客户在数据库(单租户和多租户)中创建可以通过 REST 端点访问的自定义表。所有客户都需要使用相同的公共(生产)REST 端点,这些端点将暴露在多台服务器上。但是,自定义表和关联的 REST 端点需要仅供创建它们的客户访问。这意味着我们无法将自定义表的模型写入光盘。我们需要能够在我们的生产 REST 端点的上下文中动态创建一个实际的 REST 端点。
问题:我们如何在不将模型写入光盘上的 JSON 文件的情况下,在代码中动态创建自定义 REST 端点(动态)?
您可以在模型的 JS 文件中创建一个 "remote method",这会添加 API 挂钩 "at runtime",尽管它是在启动时。也就是说,我认为您可以随时使用相同的函数来添加端点,而不仅仅是在启动时(尽管我从未尝试过):
里面/common/models/MyModel.js
module.exports = function(MyModel){
// This is the endpoint for creating endpoints...
MyModel.addEndpoint = function(name, method, cb) {
// audit name and method...
MyModel[name] = function(options, newCb) {
// do whatever this endpoint should do...
newCb(null, 'New endpoint success!');
};
MyModel.remoteMethod(
name,
{
accepts: [{arg: 'options', type: 'object'}], // or whatever you need...
returns: {arg: 'message', type: 'string'}, // whatever it returns...
http: {verb: method}
}
);
cb(null, 'Success creating new endpoint!');
};
MyModel.remoteMethod(
'addEndpoint',
{
accepts: [
{arg: 'name', type: 'string', http: {source: 'body'}},
{arg: 'method', type: 'string', http: {source: 'body'}}
],
returns: {arg: 'message', type: 'string'},
http: {verb: 'post'}
}
);
};
我在环回中也遇到过类似的问题。 我想出的解决方案是:
在我的数据库中维护一个 table [id INT, modelName VARCHAR, datasource VARCHAR, modelConfig TEXT],它可以保存任何其他 table 的模型定义。
在环回中创建一个模型(称之为 X)以提供对此 table 的 CRUD 操作。
在 X 中创建 remoteMethod 以更新应用程序对象中的模型并附加到任何数据源。 实现片段如下:
X.updateModel = (modelName, cb) => {
let app = X.app;
if (modelName) {
X.find({
where: {
name: modelName
}
}, function(err, result) {
result.forEach(row => {
let {
datasource,
modelConfig
} = row;
// Create a new model
createAndAttachModel(app, datasource, JSON.parse(modelConfig));
});
});
cb(null, "Created :" + modelName);
}
};
X.remoteMethod('updateModel', {
accepts: {arg: 'name', type: 'string'},
returns: {arg: 'result', type: 'string'},
http: {verb: 'get'},
});
let createAndAttachModel = (app, datasource, model) => {
var loopback = require("loopback");
try {
// Create a new model object using the model incoming from the database
let newModel = loopback.createModel(model);
// Attach the model to an existing datasource
app.model(newModel, {
dataSource: null,
public: true
});
let currDataSource = app.datasources[datasource];
if (currDataSource) {
newModel.attachTo(currDataSource);
} else {
console.error(datasource, "is not initialized");
}
} catch (error) {
console.error(error);
}
};