jnunemaker / httparty

Makes http fun! Also, makes consuming restful web services dead easy.

This URL has Read+Write access

httparty / lib / httparty.rb
df29a552 » jnunemaker 2008-07-27 Initial commit 1 require 'net/http'
2 require 'net/https'
3 require 'uri'
de9b4fb6 » jnunemaker 2008-07-27 Put in first wave of parsin... Comment 4 require 'ostruct'
df29a552 » jnunemaker 2008-07-27 Initial commit 5 require 'rubygems'
6 require 'active_support'
7
fda012a3 » jnunemaker 2008-11-08 Removed stupid core extensi... 8 directory = File.dirname(__FILE__)
9 $:.unshift(directory) unless $:.include?(directory) || $:.include?(File.expand_path(directory))
ae7ce309 » evri 2008-09-19 Add the ability to automati... 10
1d48da03 » jnunemaker 2008-07-28 Renamed to HTTParty which i... 11 module HTTParty
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 12 class UnsupportedFormat < StandardError; end
ae7ce309 » evri 2008-09-19 Add the ability to automati... 13 class RedirectionTooDeep < StandardError; end
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 14
df29a552 » jnunemaker 2008-07-27 Initial commit 15 def self.included(base)
16 base.extend ClassMethods
17 end
18
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 19 AllowedFormats = {:xml => 'text/xml', :json => 'application/json'}
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 20 SupportedHTTPMethods = [Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Put, Net::HTTP::Delete]
0a1737e2 » jnunemaker 2008-07-28 Added several specs for htt... 21
22 module ClassMethods
b0f1cc2a » francxk 2008-08-18 Raises exception when http ... 23 #
24 # Set an http proxy
25 #
26 # class Twitter
27 # include HTTParty
28 # http_proxy http://myProxy, 1080
29 # ....
30 def http_proxy(addr=nil, port = nil)
31 @http_proxyaddr = addr
32 @http_proxyport = port
33 end
34
df29a552 » jnunemaker 2008-07-27 Initial commit 35 def base_uri(base_uri=nil)
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 36 return @base_uri unless base_uri
0a1737e2 » jnunemaker 2008-07-28 Added several specs for htt... 37 @base_uri = normalize_base_uri(base_uri)
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 38 end
39
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 40 # Warning: This is not thread safe most likely and
41 # only works if you use one set of credentials. I
42 # leave it because it is convenient on some occasions.
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 43 def basic_auth(u, p)
44 @auth = {:username => u, :password => p}
df29a552 » jnunemaker 2008-07-27 Initial commit 45 end
46
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 47 # Updates the default query string parameters
48 # that should be appended to each request.
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 49 def default_params(h={})
50 raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
0c05dcda » jnunemaker 2008-07-28 Added #default_params metho... 51 @default_params ||= {}
52 return @default_params if h.blank?
53 @default_params.merge!(h)
54 end
55
56 def headers(h={})
57 raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
58 @headers ||= {}
59 return @headers if h.blank?
60 @headers.merge!(h)
61 end
62
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 63 def format(f)
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 64 raise UnsupportedFormat, "Must be one of: #{AllowedFormats.keys.join(', ')}" unless AllowedFormats.key?(f)
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 65 @format = f
66 end
67
68 # TODO: spec out this
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 69 def get(path, options={})
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 70 send_request Net::HTTP::Get, path, options
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 71 end
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 72
73 # TODO: spec out this
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 74 def post(path, options={})
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 75 send_request Net::HTTP::Post, path, options
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 76 end
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 77
78 # TODO: spec out this
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 79 def put(path, options={})
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 80 send_request Net::HTTP::Put, path, options
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 81 end
236b3ad4 » jnunemaker 2008-07-28 Made it so default_params a... 82
83 # TODO: spec out this
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 84 def delete(path, options={})
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 85 send_request Net::HTTP::Delete, path, options
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 86 end
87
df29a552 » jnunemaker 2008-07-27 Initial commit 88 private
b3094fc1 » jnunemaker 2008-07-30 nodoc'd some stuff 89 def http(uri) #:nodoc:
3101b531 » jnunemaker 2008-11-08 Got redirection all work pr... 90 http = Net::HTTP.new(uri.host, uri.port, @http_proxyaddr, @http_proxyport)
91 http.use_ssl = (uri.port == 443)
92 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
93 http
f4570a46 » jnunemaker 2008-07-28 base_uri is no longer requi... 94 end
95
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 96 # FIXME: this method is doing way to much and needs to be split up
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 97 # options can be any or all of:
9b423a22 » jnunemaker 2008-07-30 :body and :query now both t... 98 # query => hash of keys/values or a query string (foo=bar&baz=poo)
99 # body => hash of keys/values or a query string (foo=bar&baz=poo)
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 100 # headers => hash of headers to send request with
101 # basic_auth => :username and :password to use as basic http authentication (overrides @auth class instance variable)
b0f1cc2a » francxk 2008-08-18 Raises exception when http ... 102 # Raises exception Net::XXX (http error code) if an http error occured
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 103 def send_request(klass, path, options={}) #:nodoc:
ae7ce309 » evri 2008-09-19 Add the ability to automati... 104 options = {:limit => 5}.merge(options)
105 options[:limit] = 0 if options.delete(:no_follow)
3101b531 » jnunemaker 2008-11-08 Got redirection all work pr... 106
ae7ce309 » evri 2008-09-19 Add the ability to automati... 107 raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 108 raise ArgumentError, 'only get, post, put and delete methods are supported' unless SupportedHTTPMethods.include?(klass)
a8ff3e36 » jnunemaker 2008-07-28 Added some argument errors ... 109 raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 110 raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
3101b531 » jnunemaker 2008-11-08 Got redirection all work pr... 111
a279df8f » evri 2008-09-19 Be a little smarter with th... 112 path = URI.parse(path)
113 uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path
9b423a22 » jnunemaker 2008-07-30 :body and :query now both t... 114 existing_query = uri.query ? "#{uri.query}&" : ''
115 uri.query = if options[:query].blank?
a3f744b2 » jnunemaker 2008-08-09 Fixed that default_params w... 116 existing_query + default_params.to_query
9b423a22 » jnunemaker 2008-07-30 :body and :query now both t... 117 else
118 existing_query + (options[:query].is_a?(Hash) ? default_params.merge(options[:query]).to_query : options[:query])
119 end
3101b531 » jnunemaker 2008-11-08 Got redirection all work pr... 120
9b423a22 » jnunemaker 2008-07-30 :body and :query now both t... 121 request = klass.new(uri.request_uri)
122 request.body = options[:body].is_a?(Hash) ? options[:body].to_query : options[:body] unless options[:body].blank?
123 basic_auth = options.delete(:basic_auth) || @auth
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 124 request.initialize_http_header headers.merge(options[:headers] || {})
3a8ad1da » jnunemaker 2008-07-30 Added :basic_auth as an opt... 125 request.basic_auth(basic_auth[:username], basic_auth[:password]) if basic_auth
9b423a22 » jnunemaker 2008-07-30 :body and :query now both t... 126 response = http(uri).request(request)
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 127 @format ||= format_from_mimetype(response['content-type'])
128
b0f1cc2a » francxk 2008-08-18 Raises exception when http ... 129 case response
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 130 when Net::HTTPSuccess
b0f1cc2a » francxk 2008-08-18 Raises exception when http ... 131 parse_response(response.body)
ae7ce309 » evri 2008-09-19 Add the ability to automati... 132 when Net::HTTPRedirection
133 options[:limit] -= 1
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 134 send_request(klass, response['location'], options)
b0f1cc2a » francxk 2008-08-18 Raises exception when http ... 135 else
136 response.instance_eval { class << self; attr_accessor :body_parsed; end }
137 begin; response.body_parsed = parse_response(response.body); rescue; end
138 response.error! # raises exception corresponding to http error Net::XXX
139 end
140
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 141 end
142
b3094fc1 » jnunemaker 2008-07-30 nodoc'd some stuff 143 def parse_response(body) #:nodoc:
31ad4f91 » evri 2008-08-27 Treat nil or empty bodies s... 144 return nil if body.nil? or body.empty?
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 145 case @format
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 146 when :xml
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 147 Hash.from_xml(body)
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 148 when :json
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 149 ActiveSupport::JSON.decode(body)
de9b4fb6 » jnunemaker 2008-07-27 Put in first wave of parsin... Comment 150 else
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 151 body
de9b4fb6 » jnunemaker 2008-07-27 Put in first wave of parsin... Comment 152 end
8e143785 » jnunemaker 2008-07-27 get, post, put and delete n... 153 end
154
df29a552 » jnunemaker 2008-07-27 Initial commit 155 # Makes it so uri is sure to parse stuff like google.com with the http
bcc38bcf » jnunemaker 2008-11-08 Cleaned up base uri normali... 156 def normalize_base_uri(url) #:nodoc:
157 use_ssl = (url =~ /^https/) || url.include?(':443')
158 url.chop! if url.ends_with?('/')
159 url.gsub!(/^https?:\/\//i, '')
160 "http#{'s' if use_ssl}://#{url}"
df29a552 » jnunemaker 2008-07-27 Initial commit 161 end
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 162
76601ba0 » jnunemaker 2008-08-22 Changed format detection fr... 163 # Uses the HTTP Content-Type header to determine the format of the response
164 # It compares the MIME type returned to the types stored in the AllowedFormats hash
165 def format_from_mimetype(mimetype) #:nodoc:
166 AllowedFormats.each { |k, v| return k if mimetype.include?(v) }
13620e30 » jnunemaker 2008-07-27 Added Hash#to_struct for ma... 167 end
df29a552 » jnunemaker 2008-07-27 Initial commit 168 end
a2fd0925 » reinh 2008-11-08 Replacing string parameters... 169 end