我正在用 Express 制作一个 API,它集成了两个不同的平台,就像一座桥。假设我有一个产品 Controller ,它具有您期望的默认 CRUD 操作。
让我们创建一个产品。正常的方法是只创建一个路由,自动注入(inject)请求和资源,就像这样:
app.post('/api/products', productsController.create)
在我的 Controller 中,我会创建一个这样的函数:
const create = (req, res) =>
...
在外部调用此方法是可行的,因为在函数内部我将从请求中提取参数,然后创建产品。
但是,我有另一条路线和另一个功能可以将产品从一个地方同步到另一个地方,所以我需要在内部使用 productsController.create,但我不能使用它,因为它需要 req 和 res 来创建产品。
处理这个问题的最佳方法是什么?
我可以更改我的 Controller 函数以仅接受处理过的字段,然后在路由内部,我可以处理参数并调用该函数。唯一的问题是路线会变得更大更丑陋,而现在每条路线只有一条线。
或者我可以创建另一个模块来处理字段,然后调用创建函数,如下所示。它在路线内部稍微小了一点,但仍然比只有一条线更难看。
const create = product =>
...
app.post('/api/products', (req, res) => {
let product = treatFields(req.params)
productsController.create(product)
// send the response
})
无论如何,有人知道这样做的好方法吗?
最佳答案
在重要的 Node.js API 中,除了 Controller 之外,您通常还有一个服务层。因此, Controller 仅提取参数,有时可能会验证它们。您的服务层执行业务逻辑。
类似这样的结构:
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(“网络”)层更干净,只需传递参数而不检查,例如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.
这种方法使 whiole 的东西更具可测试性和可读性。虽然有更多文件,但与您通常的 node_modules 相比,这算不了什么 :)
关于javascript - API - 在内部和外部调用相同的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48948691/