我会尽量保持这一点,尽可能简短。
我正在编写一个以gemmat gem为模型的Ruby gem,它是产品REST API的包装器。我正在使用的API使用基于令牌的身份验证;通过POST发送API令牌,并以cookie的形式返回会话。我正在使用Faraday cookiejar中间件来处理API返回的cookie。从概念上讲,我正在努力解决的问题是何时进行身份验证。
我有两个类,一个叫做RestClient,另一个叫做Volume;后者继承自前者。现在,RestClient的init方法构建一个连接对象并进行身份验证,而Volume的init方法调用super并传递路径。我的想法是,当任何继承自RestClient的类被初始化时,它将验证用户。
class RestClient
def initialize(api_path)
<build connection>
auth
end
def auth
<post token, get session cookie>
end
end
class Volume < RestClient
def initialize
super('/volume')
end
def volumes
<send GET, receive volumes>
end
end
obj = Volume.new #Creates object, authenticates user
obj.volumes #Returns list of volumes
我想我的问题是..我走向正确的轨道?我应该暂停身份验证,直到首先在对象上调用方法,而不是在初始化时进行身份验证?我完全错误地解决了这个问题吗?
答案 0 :(得分:0)
你在这里问的更多是一个代码风格的问题。这里没有对错。我即将投票结束,因为我认为它是primarily opinion-based
。
因为我有意见,所以我会写一个答案。
a)不要过度思考
只是实现这些东西,如果有效,那就足够了
b)3的规则
如果你已经实现了3种相同类型的东西并且出现了一种模式,那么重构!
c)拒绝使用继承
如有疑问,请勿使用继承。一个模块在大多数时候都会很好。
具体问题:
我不会使用初始化程序来进行http调用。它们容易出错,并且在初始化程序或其周围的错误处理真的很难看。它使测试中的痛苦。
我要做的就是用简单的方法实现你需要的任何东西。
在拨打另一个api电话之前调用authenticate
有什么问题?将它放入一个块可能会使它非常好看和可读:
client.authenticate do |session|
session.volumes
end
如果这对你的用例来说太难看了,你可以在任何其他可能需要身份验证的方法调用之前懒散地进行。
答案 1 :(得分:0)
Cookie是您支持的唯一身份验证吗?通常,面向服务器(服务器到服务器)的REST API还可以实现更好的身份验证策略,允许您在每次请求时传递身份验证。
所有这一切,你还可以做的是这样的事情:
client = MyApi::Client.for_user(username: ..., password: ....)
#...or
client = MyApi::Client.for_token(token)
volumes = MyApi::Volumes.get(client: client)
这种方式对于需要auth的地方,你会通过“鼓励你的类正确使用”来做一件好事 - 你根本不会在没有认证数据的情况下实例化客户端,并且不会初始化你的远程没有客户的对象/电话。
然后,在客户端内,您可以做的是第一次请求时的memoized auth
def perform(http_method, url, ...)
@auth_cookie ||= @client.get_cookie_by_authentication
...
end