在重要的 Node.js API 中,除了控制器之外,您通常还有一个服务层。所以,控制器只提取参数,有时可能会验证它们。您的服务层负责业务逻辑。
类似这样的结构:
server/
controllers/
products-controller - the REST router[1]
something-else-controller - another router[1]
services/
products-service - the "business logic" [2]
现在,您的路由器(上面标记为 [1])接受参数。例如。要获取产品,他们会使用产品 ID 或产品名称:
const router = require('express').Router();
const productsService = require('../services/products-service');
router.get('/products', (req, res, next) => {
const count = req.query.count ;
// maybe validate or something
if (!count) {
return next(new Error('count param mandatory'));
}
productsService.getAllProducts(count)
.then(products => res.json(products))
.catch(err => next(err));
});
router.get('/products/:id', (req, res, next) => {
const id = req.params.id;
if (id.length !== whatever ) {
return next(new Error('Id not lookin good'));
}
productsService.getProductById(id)
.then(product => res.json(product))
.catch(err => next(err));
});
// and "another" router file, maybe products in a category
router.get('/categories/:catId/products', (req, res, next) => {
const catId = req.params.catId;
productsService.getProductByCategory(catId)
.then(products => res.json(products))
.catch(err => next(err));
});
您的服务层会执行所有数据库逻辑,可能还有“业务”验证(例如,确保电子邮件有效或产品在更新时具有有效价格等):
const productService = {
getAllProducts(count) {
return database.find(/*whatever*/)
.then(rawData => formatYourData(rawData)); // maybe strip private stuff, convert times to user's profile, whatever
// important thing is that this is a promise to be used as above
},
getProductById(id) {
if (!id) {
// foo
return Promise.reject(new Error('Whatever.'));
}
return database.findSomethingById(id)
.then(rawData => formatData(rawData)); // more of the same
},
getProductByCategory() {
return []:
}
}
现在,我混合了双方的参数验证。如果你想让你的 REST(“web”)层更干净,只需传递参数而不检查,例如productService.getProducts(req.query.page, req.query.limit).then(result => res.json(result);。并在您的服务中进行更多检查。
我什至经常将我的服务分解为多个文件,如下所示:
services/
product-service/
index.js // "barrel" export file for the whole service
get-product.js
get-products.js
create-product.js
delete-product.js
update-product.js
product.-utilsjs // common helpers, like the formatter thingy or mabye some db labels, constants and such, used in all of the service files.
这种方法使整个事情变得更加可测试和可读。虽然文件更多,但与您通常的 node_modules unholly mess 相比,这不算什么 :)