开发者

Best practice for wrapping a third party service in a library

开发者 https://www.devze.com 2023-02-28 08:31 出处:网络
I am interested in writing a library for a third party API I am using and I need some advice. The average use of the library will involve several api calls in one re开发者_高级运维quest. For example,

I am interested in writing a library for a third party API I am using and I need some advice. The average use of the library will involve several api calls in one re开发者_高级运维quest. For example, one api call to grab a user from the third party service, and then another call to use that user to grab his/her photos. Each API call will get its own library method wrapper with additional logic to handle errors/timeouts, but my biggest question is whether the library should be made as a singleton that contains state or just as a series of class methods.

For example:

user_id = ThirdParty.get_user("abc@gmail.com")
photos = ThirdParty.get_photos(user_id)

OR

thirdpartyservice = ThirdPartyService.new("abc@gmail.com")
photos = thirdpartyservice.get_photos

These doesn't have to be the exact deseign of the library, but I just am confused about the pros/cons of each approach. Any help would be amazing!

Btw, I am using ruby!


I would have the library contain the state as this reduces the complexity of code on the user side(and that's what API are supposed to do, increase simplicity). With this approach, the user doesn't have to keep track of that user_id since the library is keeping state of that.

If the user really wanted their user_id (or any other data that the library stores), you can just create an attr_reader in your library to expose that data.

To add fleixiblity for the get_photos method, you can do something like:

class ThirdPartyService

  def get_photos(user_id=@id_stored_in_library)
    # do work
  end

end

This way it defaults to the stored id, however it adds flexibility in that the user can specify the userid if he so chooses.


You need state (host, etc) and behavior based on that state so you should use objects, not one singleton object.

As mentioned, you should not name methods like get_photos, just photos.


I believe the best practice is using provider and services for the ability to not be tied down to a specific service provider. Instead of simply wrapping the library you may want to abstract it a bit and by default only allow a single service provider.

Although inheritance isn't really needed in a dynamic/duck typed language like Ruby this may help concrete the 'why'.

class MailProvider 

  def initialize(args); raise "Not Implemented"; end

  def send_mail(args); raise "Not Implemented"; end

end

class SendGridService < MailProvider

  def initialize(args)
    # Use args here
  end

  def send_mail(args)
    # Use SendGrid's API or Gem here
  end

end

Then, in your code you can have something like this:

config.mail_provider = SendGridService.new({
  username: ENV['SENDGRID_USERNAME'],
  password: ENV['SENDGRID_PASSWORD']
})

config.mail_provider.send_mail({ subject: 'woot', message: 'Look ma, I did it!' })

Then six months later when your users love your Gem/library but want MailChimp support you can simply create a second service 'MailChimpService' and allow your clients to use the new provider.


Instead of get_ set_ methods will be better to use getters and setters. It is ruby standard (not sure, but get_ and set_ methods I saw only once in ruby code).

If you don't need to save some state between requests, make it static. But it depends on many factors. Can you tell us what API you need to wrap ?

0

精彩评论

暂无评论...
验证码 换一张
取 消