我即将在 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
我正在努力弄清楚如何在不让参数变得self
的情况下使用这种模式:user_id
即{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))
你可以做些什么来创建条件路由中间件。工厂 dunction 将确定应使用哪个路由器的回调方法作为第一个参数,将路由器列表作为第二个参数,并返回有条件地使用其中一个路由的新中间战争。
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)
])
这样,只有当user_id
是数字时,才会调用instPublicProfileImageRestRoutes
。