在 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?
听起来您需要双重定义路由表。您可以稍微分解一下逻辑,以便更轻松地访问这些功能。定义一个 StudentsController
和 TeacherController
,这样你就可以定义像
这样的 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
} );
或者,您可以制作伪造的 req
和 res
对象来直接调用控制器。类似于 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
:)
我正在尝试为我的应用程序实施批处理 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?
听起来您需要双重定义路由表。您可以稍微分解一下逻辑,以便更轻松地访问这些功能。定义一个 StudentsController
和 TeacherController
,这样你就可以定义像
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
} );
或者,您可以制作伪造的 req
和 res
对象来直接调用控制器。类似于 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
:)