class Yt::HTTPRequest
A wrapper around Net::HTTP
to send HTTP requests to any web API and return their result or raise an error if the result is unexpected. The basic way to use Request is by calling run
on an instance. @example List the most popular videos on YouTube.
host = ''www.googleapis.com' path = '/youtube/v3/videos' params = {chart: 'mostPopular', key: ENV['API_KEY'], part: 'snippet'} response = Yt::Request.new(path: path, params: params).run response.body['items'].map{|video| video['snippet']['title']}
@api private
Public Class Methods
Initializes a Request object. @param [Hash] options the options for the request. @option options [Symbol] :method (:get) The HTTP method to use. @option options [String] :host The host of the request URI. @option options [String] :path The path of the request URI. @option options [Hash] :params ({}) The params to use as the query
component of the request URI, for instance the Hash +{a: 1, b: 2}+ corresponds to the query parameters +"a=1&b=2"+.
@option options [Hash] :headers ({}) The headers of the request. @option options [#size] :body The body of the request. @option options [Hash] :request_format (:json) The format of the
requesty body. If a request body is passed, it will be parsed according to this format before sending it in the request.
@option options [Proc] :error_message The block that will be invoked
when a request fails.
# File lib/yt/http_request.rb, line 33 def initialize(options = {}) @method = options.fetch :method, :get @host = options.fetch :host, 'www.googleapis.com' @path = options[:path] @params = options.fetch :params, {} @headers = options.fetch :headers, {} @body = options[:body] @request_format = options.fetch :request_format, :json @error_message = options.fetch :error_message, ->(body) {"Error: #{body}"} end
Public Instance Methods
Sends the request and returns the response with the body parsed from JSON. @return [Net::HTTPResponse] if the request succeeds. @raise [Yt::HTTPError] if the request fails.
# File lib/yt/http_request.rb, line 47 def run if response.is_a? Net::HTTPSuccess response.tap do parse_response! end else raise Yt::HTTPError.new(error_message, response: response) end end
Private Instance Methods
# File lib/yt/http_request.rb, line 88 def as_curl 'curl'.tap do |curl| curl << " -X #{http_request.method}" http_request.each_header{|k, v| curl << %Q{ -H "#{k}: #{v}"}} curl << %Q{ -d '#{http_request.body}'} if http_request.body curl << %Q{ "#{uri.to_s}"} end end
# File lib/yt/http_request.rb, line 74 def camelize(part) part.to_s.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" } end
# File lib/yt/http_request.rb, line 149 def error_message @error_message.call response.body end
@return [Net::HTTPRequest] the full HTTP request object,
inclusive of headers of request body.
# File lib/yt/http_request.rb, line 80 def http_request net_http_class = Object.const_get "Net::HTTP::#{@method.capitalize}" @http_request ||= net_http_class.new(uri.request_uri).tap do |request| set_request_body! request set_request_headers! request end end
Replaces the body of the response with the parsed version of the body, according to the format specified in the HTTPRequest
.
# File lib/yt/http_request.rb, line 143 def parse_response! if response.body response.body = JSON response.body end end
Equivalent to @params.transform_keys{|key| key.to_s.camelize :lower}
# File lib/yt/http_request.rb, line 66 def query {}.tap do |camel_case_params| @params.each_key do |key| camel_case_params[camelize key] = @params[key] end end end
Run the request and memoize the response or the server error received.
# File lib/yt/http_request.rb, line 123 def response @response ||= Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| puts as_curl if Yt.configuration.developing? http.request http_request end rescue *server_errors => e raise Yt::ConnectionError, e.message end
Returns the list of server errors worth retrying the request once.
# File lib/yt/http_request.rb, line 133 def server_errors [ Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ETIMEDOUT, Net::HTTPServerError, Net::OpenTimeout, OpenSSL::SSL::SSLError, OpenSSL::SSL::SSLErrorWaitReadable, SocketError, ] end
Adds the request body to the request in the appropriate format. if the request body is a JSON Object, transform its keys into camel-case, since this is the common format for JSON APIs.
# File lib/yt/http_request.rb, line 100 def set_request_body!(request) case @request_format when :json request.body = @body.to_json when :form request.set_form_data @body end if @body end
Adds the request headers to the request in the appropriate format. The User-Agent header is also set to recognize the request, and to tell the server that gzip compression can be used, since Net::HTTP supports it and automatically sets the Accept-Encoding header.
# File lib/yt/http_request.rb, line 113 def set_request_headers!(request) if @request_format == :json request.initialize_http_header 'Content-Type' => 'application/json' end @headers.each do |name, value| request.add_field name, value end end
@return [URI::HTTPS] the (memoized) URI of the request.
# File lib/yt/http_request.rb, line 60 def uri attributes = {host: @host, path: @path, query: URI.encode_www_form(query)} @uri ||= URI::HTTPS.build attributes end