我将在expressjs中为经过身份验证的用户和未经身份验证的用户实现REST端点。我目前对REST的了解使我采用了以下设计模式:
用户资源
令牌用户:
/users/self GET, PATCH
非令牌用户:
/users POST
/users/:user_id GET
个人资料图片资源
令牌用户:
/users/self/profile-images POST
/users/self/profile-images/:profile_image_id PUT, DELETE
非令牌用户:
/users/:user_id/profile-images GET
我正在努力弄清楚如何在不使:user_id
参数(即self
)变为{user_id: 'self'}
的情况下使用此模式。我希望它们充当两种不受干扰的隔离路径类型,一种严格,一种动态。这可能吗?如果可以,怎么办?
当前实现的代码示例如下:
// instPrivateUserRestRoutes.js (token-user)
router.use('/users/self', [
instAccountRestRoutes(restControllers),
instAuthenticationSessionRestRoutes(restControllers),
instPrivateProfileImageRestRoutes(restControllers)
])
// instPublicUserRestRoutes.js (non-token user)
router.use('/users/:user_id', [
instPublicProfileImageRestRoutes(restControllers)
])
// instRestApp.js (mount point for top resources)
router.use(instPrivateUserRestRoutes(restControllers))
router.use(instPublicUserRestRoutes(restControllers))
答案 0 :(得分:0)
如何创建条件路由中间件。工厂用法将决定使用哪个路由器的回调方法作为第一个参数,将路由器列表作为第二个参数,并返回一个新的中间战争,有条件地使用其中一条路由。
function conditionalRouting(cond, routes) {
return function (req, res, next) {
try{
// get the index for the router that should be used
var idx = cond(req, res)
// call this router and pass req, res and next to it
routes[idx](req, res, next)
} catch(err) {
// in the case an error occurs in on of the steps "throw" that error
next(err)
}
}
}
然后您可以使用这种方式:
app.use(
'/users/:user_id',
conditionalRouting(
(req, _) => req.params.user_id === 'self' ? 0:1,
[routerForSelf, routerForUser]
))
另一种方法是使用触发未发现错误的中间件显式处理这种情况:
function forceNotFound(req, res, next) {
var error = new Error('resource not found')
error.status = 404
next(error)
}
并将其添加为您的最后一个中间件
router.use('/users/self', [
instAccountRestRoutes(restControllers),
instAuthenticationSessionRestRoutes(restControllers),
instPrivateProfileImageRestRoutes(restControllers),
forceNotFound
])
这种方式很明显,快递应该在那一点上停止。
这看起来与标准Cannot GET /the/path
的外观不同,但是您通常还是不想显示这些默认错误消息。
如果您希望收到相同类型的消息,则可以编写:
var parseUrl = require('parseurl')
var encodeUrl = require('encodeurl')
app.use((req, res, next) => {
var msg = 'Cannot ' + req.method + ' ' + encodeUrl(parseUrl.original(req).pathname)
var error = new Error(msg)
error.status = 404
next(error)
})
如果您只想处理数字ID,则可以使用以下方法:
router.use('/users/:user_id(\\d+)', [
instPublicProfileImageRestRoutes(restControllers)
])
只有当instPublicProfileImageRestRoutes
是数字时,才会调用user_id
。