Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 将RESTful API重构为更小的函数_Node.js_Mongodb_Mongoose_Optimization_Code Reuse - Fatal编程技术网

Node.js 将RESTful API重构为更小的函数

Node.js 将RESTful API重构为更小的函数,node.js,mongodb,mongoose,optimization,code-reuse,Node.js,Mongodb,Mongoose,Optimization,Code Reuse,背景 我有一个NodeJS应用程序,打算用作restfulapi。它使用Mongoose与后端的MongoDB数据库连接。该应用程序基于嵌套文档的思想构建。它使用以下模式存储wiki、部分和注释: const noteSchema = new mongoose.Schema({ title: String, content: String }); const sectionSchema = new mongoose.Schema({ title: String, notes: [noteSche

背景

我有一个NodeJS应用程序,打算用作restfulapi。它使用Mongoose与后端的MongoDB数据库连接。该应用程序基于嵌套文档的思想构建。它使用以下模式存储
wiki
部分
注释

const noteSchema = new mongoose.Schema({ title: String, content: String });
const sectionSchema = new mongoose.Schema({ title: String, notes: [noteSchema] });
const wikiSchema = new mongoose.Schema({ title: String, sections: [sectionSchema] });
所有这些都可以通过单个wiki模型访问:

const wikiModel = mongoose.model("Wiki", wikiSchema);
用户可以在每个端点上执行GET、POST、PUT和DELETE请求,以操作其中的数据。如果有人想要ping Notes端点(层次结构中最下面的端点),它必须首先检查wiki,然后检查section端点,以确保每个端点都存在

下面是一个例子:

app.get('/:wikiTitle/:sectionTitle/:noteTitle', function(req, res) {
  wikiModel.findOne({ title: req.params.wikiTitle }, function(err, wiki) {
    if (err) {
      res.send('\nAn unkown error has occured');
      console.error(err);
    } else if (wiki) {
      const sectionTitle = req.params.sectionTitle;

      wikiModel.findOne({ 'sections.title': sectionTitle }, function(err, section) {
        if (err) {
          res.send('\nAn unkown error has occured');
          console.error(err);
        } else if (section) {
            const noteTitle = req.params.noteTitle;

            wikiModel.findOne({ 'sections.notes.title': noteTitle }, function(err, n) {
              if (err) {
                res.send('\nAn unkown error has occured');
                console.error(err);
              } else if (n) {
                const section = n.sections.find((s) => { return s.title === sectionTitle; });
                const note = section.notes.find((n) => { return n.title === noteTitle; });

                if (note.content) {
                  res.send('\n' + note.title + '\n\n' + note.content);
                } else {
                  res.send('\n' + note.title + '\n\n[ No content to show ]');
                }
              } else {
                res.send('\nNo such note exists');
              }
            });
        } else {
          res.send('\nNo such section exists');
        }
      });
    } else {
      res.send('\nNo such wiki exists');
    }
  });
});
这是一个非常冗长的方法,前两个查询实际上在整个应用程序中经常出现。我还理解MongoDB查询是一个异步操作,因此,我将每个后续MongoDB查询放在其父查询(我希望在开始之前完成的查询)中

问题

有没有办法将每个MongoDB查询拆分为自己的方法,或者以缩短代码的方式引入承诺?我更喜欢最终导致将代码拆分为单个方法的建议,因为您在上面看到的是使用相同查询的许多端点之一

因此,在最后的结果中,我希望有一些类似于:

app.get('/:wikiTitle/:sectionTitle/:noteTitle', function(req, res) {
  if (getWiki(req.params.wikiTitle)) {
    // Continue with second query
    if (getSection(req.params.sectionTitle)) {
      // Continue with third query...
    }
  }
});

function getWiki(wikiTitle) {
  wikiModel.findOne({ title: wikiTitle }, function(err, wiki) {
    if (err) {
      console.error(err);
      res.send('An unknown error occured.');
    } else if (wiki) {
      // Send OK result to continue to next query
      return wiki
    } else {
      res.send('No wiki found');
      return null;
    }
  });
}

function getSection(sectionTitle) {
  wikiModel.findOne({ 'sections.title': sectionTitle }, function(err, section) {
    if (err) {
      console.error(err);
      res.send('An unknown error occured.');
    } else if (section) {
      // Send OK result to continue to next query
      return section
    } else {
      res.send('No section found');
      return null;
    }
  });
}

我希望这将大大缩短代码的长度,并利用代码的可重用性。欢迎提供任何关于如何接近实现类似目标的建议。

您完全可以用调用您的模型的方法使用回调。例如:

app.get('/:wikiTitle/:sectionTitle/:notetTitle',函数(req,res){
getWiki(req.params.wikiTitle,函数(err,title){
如果(错误){
返回res.send(err);
}
getSection(req.params.sectionTitle,函数(err,section){
如果(错误){
返回res.send(err);
}
//待办事项:使用标题和章节等。。。
});
});
});
函数getWiki(wikiTitle,cb){
findOne({title:wikiTitle},函数(err,wiki){
如果(错误){
控制台错误(err);
返回cb('发生未知错误');
}else if(维基){
//发送确定结果以继续下一个查询
返回cb(null,wiki);
}否则{
返回cb(“未找到wiki”);
}
});
}
函数getSection(sectionTitle,cb){
findOne({'sections.title':sectionTitle},函数(err,section){
如果(错误){
控制台错误(err);
返回cb('发生未知错误');
}如果有的话(第节){
//发送确定结果以继续下一个查询
返回cb(空,节);
}否则{
返回cb(“未找到节”);
}
});
}
这是在节点中使用异步函数的标准方法。按照惯例,第一个参数始终是错误参数

如果希望代码更干净,可以尝试使用保护子句/提前退出来提前退出错误案例。这将减少对if/else条件语句的需要

您还可以查看库,例如异步调用的更清晰链接


当您感到舒适时,您还可以考虑使用promises和“async”javascript关键字(与上面的async库不同,我知道这会让您感到困惑),这也将允许您减少必须编写的代码行,以获得好的异步代码。

您肯定可以以调用您的模型的方式使用回调。例如:

app.get('/:wikiTitle/:sectionTitle/:notetTitle',函数(req,res){
getWiki(req.params.wikiTitle,函数(err,title){
如果(错误){
返回res.send(err);
}
getSection(req.params.sectionTitle,函数(err,section){
如果(错误){
返回res.send(err);
}
//待办事项:使用标题和章节等。。。
});
});
});
函数getWiki(wikiTitle,cb){
findOne({title:wikiTitle},函数(err,wiki){
如果(错误){
控制台错误(err);
返回cb('发生未知错误');
}else if(维基){
//发送确定结果以继续下一个查询
返回cb(null,wiki);
}否则{
返回cb(“未找到wiki”);
}
});
}
函数getSection(sectionTitle,cb){
findOne({'sections.title':sectionTitle},函数(err,section){
如果(错误){
控制台错误(err);
返回cb('发生未知错误');
}如果有的话(第节){
//发送确定结果以继续下一个查询
返回cb(空,节);
}否则{
返回cb(“未找到节”);
}
});
}
这是在节点中使用异步函数的标准方法。按照惯例,第一个参数始终是错误参数

如果希望代码更干净,可以尝试使用保护子句/提前退出来提前退出错误案例。这将减少对if/else条件语句的需要

您还可以查看库,例如异步调用的更清晰链接


当您感到舒适时,您还可以考虑使用Promissions和'async'javascript关键字(与上面的async库不同,我知道这会让您感到困惑),这也将允许您减少您必须编写的代码行,以获得好的异步代码。

您应该像这样使用异步函数(Promissions)

app.get('somePath',异步(req,res,next)=>{
试一试{
const doc=wait model.find({someField:'some value'}).exec();//exec返回承诺
res.send({document:doc});
}捕获(错误){
//在这里,您可以处理所有错误或/和调用错误中间件的下一步
下一步(错误);
}
});

您应该使用异步函数(承诺),如

app.get('somePath',异步(req,res,next)=>{
试一试{
常数