Alayde Alayde - 2 months ago 6
reST (reStructuredText) Question

Consuming REST APIs in Ruby - When to authenticate?

I'll try to keep this as brief and to the point as possible.

I'm writing a Ruby gem, modeled after the Diplomat gem, that's a wrapper around a product's REST API. The API I'm consuming makes use of token based authentication; an API token is sent via a POST, and a session is returned as a cookie. I'm making use of the Faraday cookiejar middleware for handling the cookie that's returned by the API. The problem I'm struggling with, conceptually, is when to authenticate.

I have two classes, one called RestClient and one called Volume; the latter inherits from the former. As it stands now RestClient's init method builds a connection object and authenticates, while Volume's init method calls super and passes a path. My thinking here is that when any class that inherits from RestClient is initialized it'll authenticate the user.

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


I guess my question is..am I headed down the right track? Should I hold off authenticating until a method is first called on the object, rather than authenticating when it's initialized? Am I going about this entirely incorrectly?

Answer

what you are asking here is more of a code-style question. there is no right or wrong here. i was about to vote to close because i think it is primarily opinion-based.

since i have an opinion, i'm writing an answer instead.

a) do not over-think

just implement the stuff, if it works, it is good enough

b) rule of 3

if you have implemented 3 things of the same kind and a pattern emerges, refactor!

c) refuse to use inheritance

when in doubt, do not use inheritance. a module will be good enough most of the time.

to your question specifically:

i would not use an initializer to make http calls. they are error-prone and error-handling from within initializers or around those is really ugly. it makes testing a pain in the ass.

what i would do is to just implement whatever you need in simple methods.

what is wrong with calling authenticate before making another api call? putting it into a block may make it really nice and readable:

client.authenticate do |session|
  session.volumes
end

if this is too ugly for your use-case, you could do it lazily before any other method call that might require authentication.