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'}
    }
  );
};

我在环回中也遇到过类似的问题。 我想出的解决方案是:

  1. 在我的数据库中维护一个 table [id INT, modelName VARCHAR, datasource VARCHAR, modelConfig TEXT],它可以保存任何其他 table 的模型定义。

  2. 在环回中创建一个模型(称之为 X)以提供对此 table 的 CRUD 操作。

  3. 在 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);
      }
    };