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 (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 accepts calls of the form:
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:
http://api.brightcove.com/services/library?command=find_videos_by_user_id
&user_id=34876423&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.
became just:
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:
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?



You could on a 404 or 500 response from the GET, raise the method_missing again. (Makes sense—it’ll let people know there’s no API call like that). A @@cache of methods is also usually good for stuff like this.
Cheers, Vishnu
Once you hit the method_missing call, and you have determined that it is a valid API call (e.g. via response code), you should really use define_method (http://www.ruby-doc.org/core/classes/Module.html#M001654) to dynamically create and cache that method at that point. Otherwise, every time you make an API call, it will have to go down the entire inheritance tree looking for a valid method, then down the method_missing tree.
Also, it’s a good idea to update respond_to? as well whenever you mess with method_missing (for reasons here: http://www.dcmanges.com/blog/30). Since you seem to allow any arbitrary method to be sent, one quick way would be this:
def respond_to?(method) true end
Thanks so far for your comments. David, you’re right. Your suggestions are a must.
Great write-up, Jose, much appreciated. Seems like a natural fit for and natural example of method_missing.