在 NodeJS Express 框架中处理批处理 REST API 请求

Processing Batch REST API requests in NodeJS Express framework

我正在尝试为我的应用程序实施批处理 API,客户端可以向服务器发送一组请求并期望返回单个响应。

在我的 MEAN 堆栈应用程序中使用 Express 框架。我已经创建了一个批处理 API 资源,它从客户端接收这个并且应该按照请求的每个部分中提到的 URL 来操作。

示例请求正文:

{
    "batchID": "abc123",
    "batchReq": [{
        "id": "1",
        "url": "/api/schoolm/students",
        "method": "GET",
        "value": null
    }, {
        "id": "2",
        "url": "/api/schoolm/teachers",
        "method": "POST",
        "value": {
            "name": "Teacher1",
            "age": 34
        }
    }]
}

这是发送给/api/schoolm/batch

如何将批处理控制器内部的请求分别重定向到它们各自的 API?

听起来您需要双重定义路由表。您可以稍微分解一下逻辑,以便更轻松地访问这些功能。定义一个 StudentsControllerTeacherController,这样你就可以定义像

这样的 Express 路由
app.get('/api/schoolm/students', studentController.getStudents );
app.post('/api/schoolm/teachers', teachController.postTeachers );

但仍然可以在您的批处理方法中访问它们。 编辑:您可能想要进一步分解主要逻辑,因此您可以直接调用批处理方法。

StudentController.prototype.getStudents = function(params, callback){
  //do stuff
  callback( null, studentList );
}

StudenController.prototype.getStudentsRequest = function( req, res ){
  this.getStudents( {}, function( err, students ){
    //check error
    res.send( students );
  });
}

//elsewhere, in routing table
app.get('/api/schoolm/students', studentController.getStudentsRequest );

//elsewhere, in batching method
//api route that matches students
studentController.getStudents( batchReq[index].value, function(err, students){
  //do something with students, like put in outer results object.
  //call async.each's callback(), or whatever for control flow
} );

或者,您可以制作伪造的 reqres 对象来直接调用控制器。类似于 node-mocks-http.

当然,您必须重新解析批处理对象中命名的路径,以便调用正确的控制器方法并存储结果。也许像 director 这样的东西(或内部使用的任何 express )会有所帮助。

你在 Express 中的典型路由会在最后发送它们的响应,并且 res.send 也可以调用 res.end,所以你不能真正传递它们或在其他地方使用它们(因为你不能调用 res.end 两次)。

尽管如此,为什么不直接从客户端发送多个请求。然后您也不必在客户端上解析批处理响应。我认为这将使您的

我的回答很大程度上来自 clay's 回复 borrowed/inspired/taken。我只是添加了我在案例中使用的所有细节。再次感谢粘土!

首先是我的 API 的结构:

/api/schoolm 是父级 api

然后请求被重定向到子 APIs:

/api/schoolm/students/
/api/schoolm/teachers/
/api/schoolm/subjects/
...

现在,为了支持批量操作,我添加了另一个 API 来负责处理所有批量交易。

/api/schoolm/batch/

典型的批处理请求如下所示:

{
"batchReq":[
  {
    "id":"1",
    "uri": "/api/schoolm/students/",
    "httpMethod": "GET"
  },
  {
    "id":"2",
    "uri": "/api/schoolm/teachers/",
    "httpMethod": "GET"
  }
]
}

/api/schoolm/batch 的控制器验证请求(业务逻辑)并使用参考 ID 进行响应。

var async = require('async');
var httpMocks = require('node-mocks-http');
var shortid = require('shortid');

exports.processBatch = function(batchRequests, callback){


  var batchRes = {};
  var result = {};

  var batchID = shortid.generate();
  result.batchID = batchID;

  async.setImmediate(function () {
    async.eachSeries(batchRequests, function(batchReq, callback){
      var mockRes = httpMocks.createResponse({
        eventEmitter: require('events').EventEmitter
      });

      var reqDetails = _processSubRequest(batchReq);

      _fetchResponse(reqDetails, mockRes);
      mockRes.on('end',function(){
        result[batchReq.id] = mockRes._getData();
        callback(null);
      });

    },function(err){
      console.log(result);
    });
  });

  callback("Your batch request has been accepted. Request ID - "+batchID);
}

function _processSubRequest(batchReq){
  var retValue = {};
  var request = {};
  var uriComp = batchReq.uri.split('/');
  retValue.controller = uriComp[3];

  request.method = batchReq.httpMethod;
  request.url = batchReq.uri;
  request.body = batchReq.body || {};
  request.params = batchReq.params || {};

  if(batchReq.httpMethod == 'GET'){
      if(uriComp.length > 5){
        request.params.id = uriComp[4];
      }
  }else if(batchReq.httpMethod == 'POST'){

  }else{

  }
  retValue.request = request;
  return retValue;
}

function _fetchResponse(reqDetails, mockRes){
   var mockReq  = httpMocks.createRequest(reqDetails.request);
   // proceed to fetch answer from respective controller methods.
   .......................
}

function _prepResponse(result, err, res){
  var data = {};

  if(err) {
    data["error"] = err;
    data["response"] = null;
    return data;
  }else{
    data["error"] = null;
    data["response"] = result;
    return data;
  }
}

批处理完成后,可以作为实时通知的一部分发送给用户,或者存储在数据库中供以后读取。

为批量请求开启 GraphQL:)