Implementando uma fluent interface para um webservice REST com method_missing

Nesse post vou mostrar como usar o method_missing do ruby para implementar uma fluent interface em um cliente de um webservice REST. Vamos supor um webservice imaginário com recursos que podem ser acessados nas seguintes URLs:

/recurso/id

/recurso/doTipo/algumTipo

Queremos que um cliente ruby para esse webservice forneça a seguinte fluent interface para acesso às URLs acima:

WebService.new.recurso(1).get

WebService.new.recurso.do_tipo(algumTipo).get

Uma maneira mais tradicional de se implementar esse cliente seria algo como:

require 'net/http'
require 'uri'

class WebService

  def initialize
    @url = String.new
  end

  def recurso(id = nil)
    @url << '/recurso'
    @url << "/#{id}" unless id.nil?
    self
  end

  def do_tipo(tipo)
    @url << "/doTipo/#{tipo}"
    self
  end

  def get
    response = Net::HTTP.get_response(URI.parse("http://localhost:8080#{@url}"))
    response.value
    response.body
  end

end

Repare que nos métodos recurso e do_tipo é retornado self, possibilitando o encadeamento dos métodos na fluent interface. No método get, response.value sobe uma exceção se o retorno do webservice for qualquer coisa diferente de 200 e response.body retorna o corpo do response.

Utilizando o method_missing a implementação fica bem mais simples e elegante:

require 'net/http'
require 'uri'

class WebService

  def initialize
    @url = String.new
  end

  def get
    response = Net::HTTP.get_response(URI.parse("http://localhost:8080#{@url}"))
    response.value
    response.body
  end

  def method_missing(metodo, *args)
    @url << "/#{camel_case(metodo)}"
    @url << "/#{args[0]}" if args.length > 0
    self
  end

  private

  def camel_case(metodo)
    primeira = true
    metodo.to_s.split('_').map {|palavra|
      if primeira
        primeira = false
        palavra
      else
        palavra.capitalize
      end
    }.join
  end

end

Uma característica interessante da implementação com method_missing é que ela serve para qualquer URL de qualquer recurso que já exista ou que venha a ser criada (obviamente isso só vale se houver a padronização entre a URL e a fluent interface).

About these ads

3 Responses to Implementando uma fluent interface para um webservice REST com method_missing

  1. Diogo Santos says:

    Excelente, rapá!
    O Method Missing é uma dádiva do Ruby!!! :D

  2. É mesmo… o method_missing é foda…

    Só temos que tomar cuidado pra não abusar!!!

  3. Não é uma dádiva do ruby, é uma dádiva que o ruby implementa :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: