soulim / oembed

A slim library to work with oEmbed format.
http://sul.im/oembed
MIT License
65 stars 7 forks source link

Usage for multiple providers #8

Open oyeanuj opened 8 years ago

oyeanuj commented 8 years ago

Hi @soulim! Thanks for the library, it looks great!

I had a question pertaining to my use-case which I couldn't find doc or example for. If I am looking to builder a oEmbed client that can fetch oEmbed for multiple providers, do I have to create separate classes with their endpoint_url methods? Or is there a way to pass multiple providers and have the library use that to fetch oembed data?

Thank you for open-sourcing this!

soulim commented 8 years ago

Hey @oyeanuj! Thanks for interest in using oembed gem 😄

The gem is build with the idea of having very lightweight solution for making oEmbed clients. This gives freedom and flexibility. As you see there're no predefined/hardcoded providers or request parameters. That's the idea - the gem lets you define rules and just helps with everything related to oEmbed protocol.

That said there could be many possible solutions for your specific case. I will show you just one of them, but it's totally up to which one to choose.

require 'oembed'

class Provider
  attr_reader :endpoint_uri

  def initialize(endpoint_uri, resource_pattern)
    @endpoint_uri = endpoint_uri
    @resource_pattern = resource_pattern
  end

  # Returns True if a given resource URL matches to the pattern defined for
  # the provider, or False otherwise.
  def match?(resource_uri)
    !resource_pattern.match(resource_uri).nil?
  end
end

class MultiproviderClient
  include Oembed::Client

  attr_reader :endpoint_uri

  # Adds new providers at runtime.
  # 
  # provider - a provider that must be registered on the client.
  #            See Provider class for more details.
  # 
  # Returns an Array of registered providers.
  def register_provider(provider)
    @providers << provider
  end

  # Overwritten interface of Oembed::Client. Every time a resource is fetched
  # a client is looking for a suitable provider.
  # 
  # The method could be improved for cases when no provider is found.
  def fetch!(resource_uri, params = {})
    @endpoint_uri = endpoint_uri_for(resource_uri)
    super(resource_uri, params = {})
  end

  private

  def providers
    @providers ||= []
  end

  def endpoint_uri_for(resource_uri)
    providers.find { |provider| provider.match?(resource_uri) }
  end
end

# Example

client = MultiproviderClient.new
# Endpoint URL and patterns could be also loaded from configration file,
# database, or remote API.
providers = [
  Provider.new('https://www.youtube.com/oembed', /^.*youtube.com.*$/),
  Provider.new('http://api.instagram.com/oembed', /^.*instagr.*$/),
  Provider.new('http://www.flickr.com/services/oembed.xml', /^.*flickr.com.*$/)
]

providers.each { |provider| client.register_provider(provider) }

client.fetch('http://www.flickr.com/photos/alex_soulim/3593916989')
# => oEmbed data for the Flickr resource

client.fetch('http://instagr.am/p/BUG/', maxwidth: 300)
# => oEmbed data for the Instagram resource

Note: I didn't have time to play with the code above, so some minor tweaks might be required. I just wanted to demonstrate you a possible solution.