vinibaggio.net

Criando um Responder para JSONP no Rails 3

Recentemente eu tive que implementar uma feature no call4paperz que é responder dados dos eventos do site em JSONP.

JSONP é na verdade bem similar com a resposta JSON que o site já tinha, porém a resposta não mais é JSON puro, e sim um código JavaScript que chama um callback especificado. Quando a resposta do servidor for executada, esse callback é chamado automaticamente. Exemplo:

my_callback({"foo": "bar"});

Mas, para dar esse suporte, eu não queria arruinar os controllers que já estavam simples e elegantes, com o respond_with:

class EventsController < ApplicationController
    respond_to :json, :xml, :html

    def index
        @events = Event.all
        respond_with @events
    end

    # ...
end

Obviamente, senti a necessidade de criar um novo formato de resposta na aplicação. A API de Responders no Rails 3 funciona muito bem para isso. Dessa forma, eu:

  • Adicionei um handler JSONP para o meu Responder já existente (eu uso a gem responders);
  • Adicionei um Mime type para isso;
  • Adicionei respond\_to :jsonp ao controller.

Adicionar um handler JSONP

Como eu já tinha um Responder devido a gem, eu simplesmente adicionei o método to_jsonp a ele:

lib/jsonp_responder.rb

module JSONPResponder
  def to_jsonp
    render :json => "#{callback}(#{resource.to_json});"
  end

  private
  def callback
    controller.params[:callback]
  end
end

lib/application_responder.rb

class ApplicationResponder < ActionController::Responder
  include Responders::FlashResponder
  include Responders::HttpCacheResponder
  include JSONPResponder
end

Adicionar um Mime type

Como não há de fato um Mime type específico para JSONP, o site deverá responder como application/javascript, já que não respondemos mais JSON válido.

config/initializers/mime_types.rb

Mime::Type.register_alias "application/javascript", :jsonp

Adicionar respond_to :jsonp ao controller

Esse é o passo mais simples de todos:

class EventsController < ApplicationController
    respond_to :json, :jsonp, :xml, :html

    def index
        @events = Event.all
        respond_with @events
    end

    # ...
end

Finito!

Simples, não? O código do controller continua limpo como deveria ser, graças à API de Responders do Rails 3. Mais informações sobre ele pode ser visto em um blog post do próprio Rails.


Written by Vinicius Baggio Fuentes, who works in tech in NY and loves being in the kitchen in the remaining time. Twitter Instagram