Ruby wrapper for Google App Engine URL Fetch service

I am still playing with my Sinatra app, running on GAE. Just in case if do that too… and might need to fetch some external data, following is a wrapper code I’m using :

require 'java'

module UrlFetch
  
  module UF
    import java.net.URL;
    import java.net.URLEncoder;    
    import com.google.appengine.api.urlfetch.HTTPHeader
    import com.google.appengine.api.urlfetch.HTTPMethod
    import com.google.appengine.api.urlfetch.HTTPRequest
    import com.google.appengine.api.urlfetch.HTTPResponse
    import com.google.appengine.api.urlfetch.URLFetchService
    import com.google.appengine.api.urlfetch.URLFetchServiceFactory
    
    Service = URLFetchServiceFactory.getURLFetchService()
  end
  
  module InstanceMethods
    def fetch_url(options = {})
      self.class.fetch_url(options)
    end

  end

  module ClassMethods
  
    # = Fetch URL proxy
    # === Accepted options:
    # :url     - request url
    # :method  - HTTP method ('get', 'post' ..)
    # :headers - hash of request headers
    # :params  - request params. Only valid if the method is post
    #
    # === Response:
    # Rack stype responce:
    # [response_code, headers, body]
    
    def fetch_url(options = {})
      return nil unless (options[:url])
      
      url = UF::URL.new(options[:url])
      request = UF::HTTPRequest.new(url, UF::HTTPMethod.valueOf((options[:method] || 'get').upcase))
      
      options[:headers].each{|name, value| request.addHeader(UF::HTTPHeader.new(name, value))} if options[:headers] && options[:headers].is_a?(Hash)
      
      if options[:method] == 'post' && options[:params]
        payload = options[:params].collect{|name, value| "#{UF::URLEncoder.encode(name, 'UTF-8')}=#{UF::URLEncoder.encode(value, 'UTF-8')}" }
        request.setPayload(payload.to_java_bytes)
      end
      response = UF::Service.fetch(request)
      [
        response.getResponseCode,
        response.getHeaders().inject({}){|hash, header| hash[header.name] = header.value; hash },
        (String.from_java_bytes(response.getContent) if response.getContent)
      ]
    rescue => e
      [500, {}, e.to_s]
    end

  end
  
  def self.included(base)
    base.send :include, InstanceMethods
    base.send :extend,  ClassMethods
  end
  
end

I hope this is will save some typing 🙂

Here is a link to GitHub gist: git clone git://gist.github.com/111006.git gist-111006