Skip to content

Instantly share code, notes, and snippets.

@sergeych
Created December 5, 2015 14:18
Show Gist options
  • Save sergeych/b3bc51acc3acc08c1318 to your computer and use it in GitHub Desktop.
Save sergeych/b3bc51acc3acc08c1318 to your computer and use it in GitHub Desktop.
Easy took to perform http request with pool and keep-alive support
require 'net/http'
require 'uri'
require 'json'
require 'hashie'
# Simple HTTP access, with embed JSON parsing, pooling and keep-alive support. Especially useful
# for API access over https. Requires json support and gem 'hashie'.
#
# v2 by real.sergeyhch@gmail.com
#
# Synopsis:
#
# connection = Httpick.new(url)
# connection.get path, [ ,headers: [] ], **params
#
# also available methods: post, put, patch, delete and head
#
# For more control see #request
#
class Httpick
@@connections = {}
# Create Httpick to acces a given host. Actual http connection will be either
# taken from a pool or created (to use keep-alive at its best)
def initialize uri
uri.is_a?(URI) or uri = URI.parse(uri)
@conn = @@connections[uri.host] ||= begin
c = Net::HTTP.new(uri.host, uri.port)
c.use_ssl = uri.scheme == 'https'
c.start
end
@uri = uri
end
# Perform a request on the current connection, to use when the method could vary.
#
# @param [Object] method
# @param [Object] path if not set, used uri passed on initialization
# @param [Hash] headers
# @param [Hash] params
# @return [Httpick] instance, so you can chain it like httpick.request().json or like
def request method, path: nil, headers: {}, params: {}
path = path || @uri.path
if method == 'GET' && params.size > 0
path = path + '?' + params.map { |k, v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&')
end
@req = case method
when 'GET'
Net::HTTP::Get.new(path)
when 'PUT'
Net::HTTP::Put.new(path)
when 'POST'
Net::HTTP::Post.new(path)
when 'PATCH'
Net::HTTP::Patch.new(path)
when 'DELETE'
Net::HTTP::Delete.new(path)
when 'HEAD'
Net::HTTP::Head.new(path)
else
raise ArgumentError, "unknown http method #{method}"
end
headers.each { |k, v|
@req[k.to_s] = v.to_s
}
# p [:r, method, @uri.to_s, path, params]
if method != 'GET' && params && params.size > 0
@req.set_form_data params
end
@response = @conn.request @req
self
end
# Perfrom request using connection pool/keep alive as possible
# (userful to speed up sequences of https calls)
def self.request uri, method: :get, headers: {}, params: {}
method = method.to_s.upcase
uri.is_a?(String) and uri = URI.parse(uri)
h = HttpUtil.new uri
h.request method, headers: headers, params: params
end
# response body
def body
@response.body
end
# Parse body that should be JSON
# @return [Hashie::Mash] parsed body
def json
b = @response.body || "{}"
Hashie::Mash.new JSON.parse(b)
end
# Same as #status
def code
@response.code.to_i
end
# response status as an integer value
def status
code
end
%w[get post put delete patch head].each do |m|
Httpick.class_eval <<-End
def #{m}(path, headers:{}, **params)
request '#{m.upcase}', path: path, headers: headers, params: params
end
End
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment