【发布时间】:2018-12-22 03:40:18
【问题描述】:
场景:我需要让模型访问存储在会话中的 API 令牌。
背景:我有一个 API 驱动的 rails 3 应用程序,它使用 DataMapper(DM) 和一个 DM 适配器来与 API 交互。每个 DM 模型都有一个对应的 REST-ish API 端点,就像使用 rails 脚手架一样。 API 需要各种请求标头,包括 API 令牌、密钥、ID 等。标头与请求的数据无关,它们仅用于授权和跟踪目的。许多这些令牌存储在会话中。我想要一种干净的方式让这些 API 标头在请求期间可用于任何模型。
可能的解决方案:
1。将会话变量从控制器传递给模型
显而易见的答案是将哈希或其他对象中的令牌从控制器传递给模型。控制器操作可能具有以下内容:@user = User.find(params[:id], api_headers)。
问题是需要重写任何模型方法来接受额外的api_headers 对象。不计算 Rails 和 DataMapper 定义的方法,应用程序模型中已经定义了数百个方法需要重写。所以我排除了重写,这似乎也不是一个好的解决方案,因为它需要覆盖大量的 DM 方法,比如上面的 User#find 示例。
2。一些元编程技巧
我可以在 DM 的基类上捕获任何 ArgumentError 并检查最后一个参数是否是 api_headers 对象,然后将值设置为实例变量并调用请求的方法。这个思考练习已经让我在处理可选参数等方面感到畏缩。如果给的时间足够长,我可能会创建一个功能性的弗兰肯斯坦,它应该让我被解雇但可能不会。
3。使用单例(当前首选的解决方案)
在应用程序控制器中设置一个 before_filter 以将会话存储的 API 标头转储到单个 ApiHeaders 对象中。然后,任何发出 API 请求的模型都可以使用所需的 API 标头获取该单例。
应用程序控制器上的额外after_filter* 将在请求结束时将ApiHeaders 单例上的所有属性设置为nil,以防止请求之间的标头泄漏。
这是我目前首选的解决方案,但我不喜欢如果 after_filter 没有被调用,API 标头值可能会转移到其他请求中。我不知道在哪些情况下可能会发生这种情况(可能是应用程序错误?)这引起了人们的关注。我所知道的是值不一定会随着请求而消失。
4。自定义代码
放弃对 DataMapper 和自定义 API 适配器的支持,并手动进行所有 API 调用,传递所有必需的 API 标头。除了我没有时间进行这种级别的重写之外,如果您必须抛出一大块来支持自定义身份验证方案,为什么还要使用框架?
总结
将这些令人讨厌的 API 令牌从会话中获取到应用程序的内部,并在每个 API 请求中发送它们的最干净的方法是什么?我希望有比上面列出的更好的解决方案。
* after_action 的别名
【问题讨论】:
-
我使用过很多 API。我从未将我的 api 令牌传递给模型。您做出该设计决定的原因是什么?
-
是的,请解释一下这个决定。我认为控制器会根据标题做出逻辑决策,而不是
User模型。 -
这是一个 REST API,每个模型都由一个端点支持。所以
User.find(:id)调用/api/users/:id。每个 DM 模型都通过一个适配器,该适配器调用 API 并将 json 响应转换为模型的实例。适配器是在应用程序级别配置的,但所需的大多数 API 标头都是特定于登录用户的。
标签: ruby-on-rails ruby ruby-on-rails-3 api session