We love open source and we invest in continuous learning. We give back our knowledge to the community.

José Costa

Method Missing to Simplify Queries to an External Service

Comments

I know there are several discussions on the usage of method_missing in Ruby. In this post i’ll present a pretty simple, yet useful solution that uses method_missing to interact with the Brightcove Media Read API(Getting Started with the Media API) (you don’t need to be familiar with this service, i’ll explain a little bit in the next few lines).

Brightcove Media Read API(Getting Started with the Media API) accepts calls of the form:

1
2
3
4
5
6
7
8
http://api.brightcove.com/services/library?command=find_all_videos
&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.

http://api.brightcove.com/services/library?command=find_related_videos
&video_id=123123&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.

http://api.brightcove.com/services/library?command=find_videos_by_text
&text=sometextsample&pageSize=100&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.

A token must be passed on each call, and you could also add more parameters like you would do in a regular GET request. What comes back is a JSON string that can be easily picked up.

The key thing here is to notice that there are several commands you could execute from the API, naturally each with its own name that must be specified in the request right after command=“. Since the “API also provides a set of error codes to address all wrong requests or non-existent commands requests, we simply wanted to forward all the calls to the API and reply back with its answer. So, in order to avoid defining all API methods in our Ruby module, we just used the method_missing and forwarded all calls to it, using the name of the method as the API command.

The idea was that a call like:

1
2
http://api.brightcove.com/services/library?command=find_videos_by_user_id
&user_id=34876423&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.

became just:

1
Brightcove::ReadProxy.find_videos_by_user_id :user_id => 34876423

We then implemented what we called the Brightcove::ReadProxy in a few lines like shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module Brightcove
  module ReadProxy

    TOKEN = '0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.'
    SITE = 'http://api.brightcove.com/services/library'

    def self.method_missing(method_id, *args)
      args[0] ||= { }
      args[0].merge!({ :command => method_id, :token => TOKEN })
      get SITE, args[0]
    end

    def self.get(url, params)
      http_client = HTTPClient.new
      result = http_client.get(url, params)
      content = nil
      begin
        content = JSON.parse(result.content)
      rescue Exception => e
        Rails.logger.error e.message
      end
      return content
    end

 end

Basically all the magic relies in the method_missing that would convert any call to the Brightcove::ReadProxy module in the format accepted by the API, without having to define every API method and maintaining the Rails like finders syntax. We also used the httpclient gem to simplify the GET request calls and the json gem to parse the result of the call.

I’m not saying that this is the best usage, but i think in this particular situation it suits pretty well.

What do you think?

Comments