如何解决将RESTful API重构为较小的功能
背景
我有一个NodeJS应用程序,打算用作RESTful API。它使用Mongoose与后端的MongoDB数据库连接。该应用程序基于嵌套文档的想法而构建。它使用以下架构存储wikis
,sections
和notes
:
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 },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 },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',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 },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 },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/:noteTitle',function(req,res) {
getWiki(req.params.wikiTitle,function (err,title) {
if (err) {
return res.send(err);
}
getSection(req.params.sectionTitle,section) {
if (err) {
return res.send(err);
}
// Todo: use title and section,etc...
});
});
});
function getWiki(wikiTitle,cb) {
wikiModel.findOne({ title: wikiTitle },function(err,wiki) {
if (err) {
console.error(err);
return cb('An unknown error occured.');
} else if (wiki) {
// Send OK result to continue to next query
return cb(null,wiki);
} else {
return cb('No wiki found');
}
});
}
function getSection(sectionTitle,cb) {
wikiModel.findOne({ 'sections.title': sectionTitle },section) {
if (err) {
console.error(err);
return cb('An unknown error occured.');
} else if (section) {
// Send OK result to continue to next query
return cb(null,section);
} else {
return cb('No section found');
}
});
}
这是在节点中使用异步功能的标准方法。按照惯例,第一个参数始终是错误参数。
如果希望代码更整洁,可以尝试使用保护子句/提早退出,以尽早退出错误情况。这将减少您对if / else条件语句的需求。
您还可以查看类似async的库,以更清晰地链接异步调用。
在您感到舒适的时候,您还可以研究使用Promise和'async'javascript关键字(与上面的async库不同,我知道这很令人困惑),这也将使您减少拥有的代码行编写以获得不错的异步代码。
,您应该使用异步功能(Promise),例如
app.get('somePath',async (req,res,next) => {
try {
const doc = await model.find({ someField: 'some value' }).exec(); // exec returns promise
res.send({ document: doc });
} catch (error) {
// here you can handle all errors or/and call next for the error middleware
next(error);
}
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。