如何制作 运行 API 端点?

How to make a running API endpoint?

我想知道如何将 运行 端点设为 RunKit does

在 RunKit 的那个页面中,它生成一个与代码关联的 URL。在浏览器中打开 URL 将看到代码定义的 response。此外,代码的更改将实时反映。

有谁知道他们是如何做到这一点的?

我知道在 mean-stack 网站中定义一个固定的 api。例如,https://myexample.com/api/add/3/5可以调用,因为下面的代码。但是我不知道如何制作一个可以实时更改功能的API

router.get('/api/add/:a/:b', function (req, res, next) {
    var r = Number(req.params.a) + Number(req.params.b);
    res.json(r)
})

Express 中间件只是普通的 JS 函数。

为了拥有功能不断变化的路由,您无需在运行时更改中间件功能,只需更改其行为方式即可。

我会尝试在这里展示一个可能的解决方案。
请注意,这只是一个概念验证,而不是生产就绪的 and/or 安全解决方案。


假设您的网站上有某种在线代码编辑器,允许您的用户编写 JS 代码并将其保存在您的数据库中。

您可以像这样设置端点路由:

router.get('/endpoint/:id', (req, res) => {
  // this id identifies a previously saved code wrote by a user
  let id = req.params.id        

  // NOTE: THIS IS NOT ACTUAL WORKING JS CODE
  // fetch the previously saved code from your database as a string
  let code = database.getDocumentById(id)

  // you can construct an actual JS function form the string, using the `Function()` constructor
  let f = Function(code)

  // now you can call the function, do whatever you like with it and finally send the user the results
  let result = f()
  res.send(result)
})

您可能需要为用户提供的代码创建包装函数并控制将执行的内容和结果。


P.S.
另请查看关于从字符串创建 JS 函数的 SO post:
Is there a way to create a function from a string with javascript?

基本思想是,您创建一个存储为字符串的函数数据库。由于 JS 允许您使用 Function() 构造函数从字符串创建函数,因此您可以根据需要动态生成函数。我提供了一个 POST 端点来注册该函数。

var express = require("express");
var app = express();
var bodyParser = require('body-parser');
var router = express.Router();
var mongoose = require('mongoose');

db = mongoose.connect('mongodb://localhost:27017/login1');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

var data = new mongoose.Schema({
    "name": String,
    "content": String
});
model = mongoose.model("functions", data);

router.post('/create', (req, res) => {
    // Insert validation for security and removing duplicates etc.
    model.insertMany({"name": req.body.name, "content": req.body.content}).then((d, err) => {
        res.status(200).send({'result': "Added"});
    });
});

router.get('/:func/*', (req, res) => {
    var func = req.params.func;
    var args = req.params['0'].split('/');
    model.findOne({"name": func}).then((d, err) => {
        if (err) {return res.status(404).send({'result': "Error with database"});}
        else if (d === null) {return res.status(202).send({'result': "Function not present"});}
        var func = Function(d.content);
        res.status(200).send({'result': func(...args)});
    });
});

app.use("/", router);
var port = process.env.PORT || 3000;

var server = app.listen(port, function() {
    console.log('Express server listening on port ' + port);
});

让我们测试一下:

$ node server.js
Express server listening on port 3000

来自邮递员或其他终端window:

$ curl -X GET "http://localhost:3000/add/1/2/3"
{"result":"Function not present"} 

现在让我们注册 add 函数(即 sum of arguments):

$ curl -X POST "http://localhost:3000/create/" -H "content-type:application/json" -d '{"name": "add", "content": "return [...arguments].reduce( (i, j) => i+=parseInt(j), 0);"}'
{'result': "Added"}

这里注册的函数要复杂得多。请记住,您可以使用 Agruments 变量获取传递给函数的所有参数。

测试一下:

$ curl -X GET "http://localhost:3000/add/1/2/3"
{"result": 6}

$ curl -X GET "http://localhost:3000/add/100/3/5/10/9/2"
{"result": 129}