larsburgess-rest-client 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,269 @@
1
+ = REST Client -- simple DSL for accessing HTTP and REST resources
2
+
3
+ A simple HTTP and REST client for Ruby, inspired by the Sinatra's microframework style
4
+ of specifying actions: get, put, post, delete.
5
+
6
+ * Main page: http://github.com/archiloque/rest-client
7
+ * Mailing list: rest.client@librelist.com (send a mail to subscribe).
8
+ * IRC: #rest-client at freenode
9
+
10
+ == Usage: Raw URL
11
+
12
+ require 'rest_client'
13
+
14
+ RestClient.get 'http://example.com/resource'
15
+
16
+ RestClient.get 'http://example.com/resource', {:params => {:id => 50, 'foo' => 'bar'}}
17
+
18
+ RestClient.get 'https://user:password@example.com/private/resource', {:accept => :json}
19
+
20
+ RestClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' }
21
+
22
+ RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json
23
+
24
+ RestClient.delete 'http://example.com/resource'
25
+
26
+ response = RestClient.get 'http://example.com/resource'
27
+ response.code
28
+ ➔ 200
29
+ response.cookies
30
+ ➔ {"Foo"=>"BAR", "QUUX"=>"QUUUUX"}
31
+ response.headers
32
+ ➔ {:content_type=>"text/html; charset=utf-8", :cache_control=>"private" ...
33
+ response.to_str
34
+ ➔ \n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n \"http://www.w3.org/TR/html4/strict.dtd\">\n\n<html ....
35
+
36
+ RestClient.post( url,
37
+ {
38
+ :transfer => {
39
+ :path => '/foo/bar',
40
+ :owner => 'that_guy',
41
+ :group => 'those_guys'
42
+ },
43
+ :upload => {
44
+ :file => File.new(path, 'rb')
45
+ }
46
+ })
47
+
48
+ == Multipart
49
+
50
+ Yeah, that's right! This does multipart sends for you!
51
+
52
+ RestClient.post '/data', :myfile => File.new("/path/to/image.jpg", 'rb')
53
+
54
+ This does two things for you:
55
+
56
+ * Auto-detects that you have a File value sends it as multipart
57
+ * Auto-detects the mime of the file and sets it in the HEAD of the payload for each entry
58
+
59
+ If you are sending params that do not contain a File object but the payload needs to be multipart then:
60
+
61
+ RestClient.post '/data', :foo => 'bar', :multipart => true
62
+
63
+ == Usage: ActiveResource-Style
64
+
65
+ resource = RestClient::Resource.new 'http://example.com/resource'
66
+ resource.get
67
+
68
+ private_resource = RestClient::Resource.new 'https://example.com/private/resource', 'user', 'pass'
69
+ private_resource.put File.read('pic.jpg'), :content_type => 'image/jpg'
70
+
71
+ See RestClient::Resource module docs for details.
72
+
73
+ == Usage: Resource Nesting
74
+
75
+ site = RestClient::Resource.new('http://example.com')
76
+ site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
77
+
78
+ See RestClient::Resource docs for details.
79
+
80
+ == Exceptions (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
81
+
82
+ * for results code between 200 and 207 a RestClient::Response will be returned
83
+ * for results code 301, 302 or 307 the redirection will be followed if the request is a get or a head
84
+ * for result code 303 the redirection will be followed and the request transformed into a get
85
+ * for other cases a RestClient::Exception holding the Response will be raised, a specific exception class will be thrown for know error codes
86
+
87
+ RestClient.get 'http://example.com/resource'
88
+ ➔ RestClient::ResourceNotFound: RestClient::ResourceNotFound
89
+
90
+ begin
91
+ RestClient.get 'http://example.com/resource'
92
+ rescue => e
93
+ e.response
94
+ end
95
+ ➔ 404 Resource Not Found | text/html 282 bytes
96
+
97
+ == Result handling
98
+
99
+ A block can be passed to the RestClient method, this block will then be called with the Response.
100
+ Response.return! can be called to invoke the default response's behavior.
101
+
102
+ # Don't raise exceptions but return the response
103
+ RestClient.get('http://example.com/resource'){|response, request, result| response }
104
+ ➔ 404 Resource Not Found | text/html 282 bytes
105
+
106
+ # Manage a specific error code
107
+ RestClient.get('http://my-rest-service.com/resource'){ |response, request, result, &block|
108
+ case response.code
109
+ when 200
110
+ p "It worked !"
111
+ response
112
+ when 423
113
+ raise SomeCustomExceptionIfYouWant
114
+ else
115
+ response.return!(request, result, &block)
116
+ end
117
+ }
118
+
119
+ # Follow redirections for all request types and not only for get and head
120
+ # RFC : "If the 301, 302 or 307 status code is received in response to a request other than GET or HEAD,
121
+ # the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user,
122
+ # since this might change the conditions under which the request was issued."
123
+ RestClient.get('http://my-rest-service.com/resource'){ |response, request, result, &block|
124
+ if [301, 302, 307].include? response.code
125
+ response.follow_redirection(request, result, &block)
126
+ else
127
+ response.return!(request, result, &block)
128
+ end
129
+ }
130
+
131
+ == Non-normalized URIs.
132
+
133
+ If you want to use non-normalized URIs, you can normalize them with the addressable gem (http://addressable.rubyforge.org/api/).
134
+
135
+ require 'addressable/uri'
136
+ RestClient.get(Addressable::URI.parse("http://www.詹姆斯.com/").normalize.to_str)
137
+
138
+ == Lower-level access
139
+
140
+ For cases not covered by the general API, you can use the RestClient::Resource class which provide a lower-level API, see the class' rdoc for more information.
141
+
142
+ == Shell
143
+
144
+ The restclient shell command gives an IRB session with RestClient already loaded:
145
+
146
+ $ restclient
147
+ >> RestClient.get 'http://example.com'
148
+
149
+ Specify a URL argument for get/post/put/delete on that resource:
150
+
151
+ $ restclient http://example.com
152
+ >> put '/resource', 'data'
153
+
154
+ Add a user and password for authenticated resources:
155
+
156
+ $ restclient https://example.com user pass
157
+ >> delete '/private/resource'
158
+
159
+ Create ~/.restclient for named sessions:
160
+
161
+ sinatra:
162
+ url: http://localhost:4567
163
+ rack:
164
+ url: http://localhost:9292
165
+ private_site:
166
+ url: http://example.com
167
+ username: user
168
+ password: pass
169
+
170
+ Then invoke:
171
+
172
+ $ restclient private_site
173
+
174
+ Use as a one-off, curl-style:
175
+
176
+ $ restclient get http://example.com/resource > output_body
177
+
178
+ $ restclient put http://example.com/resource < input_body
179
+
180
+ == Logging
181
+
182
+ To enable logging you can
183
+
184
+ * set RestClient.log with a ruby Logger
185
+ * or set an environment variable to avoid modifying the code (in this case you can use a file name, "stdout" or "stderr"):
186
+
187
+ $ RESTCLIENT_LOG=stdout path/to/my/program
188
+
189
+ Either produces logs like this:
190
+
191
+ RestClient.get "http://some/resource"
192
+ # => 200 OK | text/html 250 bytes
193
+ RestClient.put "http://some/resource", "payload"
194
+ # => 401 Unauthorized | application/xml 340 bytes
195
+
196
+ Note that these logs are valid Ruby, so you can paste them into the restclient
197
+ shell or a script to replay your sequence of rest calls.
198
+
199
+ == Proxy
200
+
201
+ All calls to RestClient, including Resources, will use the proxy specified by
202
+ RestClient.proxy:
203
+
204
+ RestClient.proxy = "http://proxy.example.com/"
205
+ RestClient.get "http://some/resource"
206
+ # => response from some/resource as proxied through proxy.example.com
207
+
208
+ Often the proxy url is set in an environment variable, so you can do this to
209
+ use whatever proxy the system is configured to use:
210
+
211
+ RestClient.proxy = ENV['http_proxy']
212
+
213
+ == Cookies
214
+
215
+ Request and Response objects know about HTTP cookies, and will automatically
216
+ extract and set headers for them as needed:
217
+
218
+ response = RestClient.get 'http://example.com/action_which_sets_session_id'
219
+ response.cookies
220
+ # => {"_applicatioN_session_id" => "1234"}
221
+
222
+ response2 = RestClient.post(
223
+ 'http://localhost:3000/',
224
+ {:param1 => "foo"},
225
+ {:cookies => {:session_id => "1234"}}
226
+ )
227
+ # ...response body
228
+
229
+ == SSL Client Certificates
230
+
231
+ RestClient::Resource.new(
232
+ 'https://example.com',
233
+ :ssl_client_cert => OpenSSL::X509::Certificate.new(File.read("cert.pem")),
234
+ :ssl_client_key => OpenSSL::PKey::RSA.new(File.read("key.pem"), "passphrase, if any"),
235
+ :ssl_ca_file => "ca_certificate.pem",
236
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER
237
+ ).get
238
+
239
+ Self-signed certificates can be generated with the openssl command-line tool.
240
+
241
+ == Hook
242
+
243
+ RestClient.add_before_execution_proc add a Proc to be called before each execution, it's handy if you need a direct access to the http request.
244
+
245
+ Example:
246
+
247
+ # Add oath support using the oauth gem
248
+ require 'oauth'
249
+ access_token = ...
250
+
251
+ RestClient.add_before_execution_proc do |req, params|
252
+ access_token.sign! req
253
+ end
254
+
255
+ RestClient.get 'http://example.com'
256
+
257
+ == More
258
+
259
+ Need caching, more advanced logging or any ability provided by a rack middleware ?
260
+
261
+ Have a look at rest-client-components http://github.com/crohr/rest-client-components
262
+
263
+ == Meta
264
+
265
+ Written by Adam Wiggins, major modifications by Blake Mizerany, maintained by Julien Kirch
266
+
267
+ Patches contributed by many, including Chris Anderson, Greg Borenstein, Ardekantur, Pedro Belo, Rafael Souza, Rick Olson, Aman Gupta, François Beausoleil and Nick Plante.
268
+
269
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -0,0 +1,69 @@
1
+ require 'rake'
2
+
3
+ require 'jeweler'
4
+
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "larsburgess-rest-client"
7
+ s.description = "A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete."
8
+ s.summary = "Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions."
9
+ s.author = "Adam Wiggins"
10
+ s.email = "rest.client@librelist.com"
11
+ s.homepage = "http://github.com/archiloque/rest-client"
12
+ s.rubyforge_project = "rest-client"
13
+ s.has_rdoc = true
14
+ s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
15
+ s.executables = %w(restclient)
16
+ s.add_dependency("mime-types", ">= 1.16")
17
+ s.add_development_dependency("webmock", ">= 0.9.1")
18
+ s.add_development_dependency("rspec")
19
+ end
20
+
21
+ Jeweler::RubyforgeTasks.new
22
+
23
+ ############################
24
+
25
+ require 'spec/rake/spectask'
26
+
27
+ desc "Run all specs"
28
+ task :spec => ["spec:unit", "spec:integration"]
29
+
30
+ desc "Run unit specs"
31
+ Spec::Rake::SpecTask.new('spec:unit') do |t|
32
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
33
+ t.spec_files = FileList['spec/*_spec.rb']
34
+ end
35
+
36
+ desc "Run integration specs"
37
+ Spec::Rake::SpecTask.new('spec:integration') do |t|
38
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
39
+ t.spec_files = FileList['spec/integration/*_spec.rb']
40
+ end
41
+
42
+ desc "Print specdocs"
43
+ Spec::Rake::SpecTask.new(:doc) do |t|
44
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
45
+ t.spec_files = FileList['spec/*_spec.rb']
46
+ end
47
+
48
+ desc "Run all examples with RCov"
49
+ Spec::Rake::SpecTask.new('rcov') do |t|
50
+ t.spec_files = FileList['spec/*_spec.rb']
51
+ t.rcov = true
52
+ t.rcov_opts = ['--exclude', 'examples']
53
+ end
54
+
55
+ task :default => :spec
56
+
57
+ ############################
58
+
59
+ require 'rake/rdoctask'
60
+
61
+ Rake::RDocTask.new do |t|
62
+ t.rdoc_dir = 'rdoc'
63
+ t.title = "rest-client, fetch RESTful resources effortlessly"
64
+ t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
65
+ t.options << '--charset' << 'utf-8'
66
+ t.rdoc_files.include('README.rdoc')
67
+ t.rdoc_files.include('lib/*.rb')
68
+ end
69
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.6.1
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+ require 'restclient'
5
+
6
+ require "yaml"
7
+
8
+ def usage(why = nil)
9
+ puts "failed for reason: #{why}" if why
10
+ puts "usage: restclient [get|put|post|delete] url|name [username] [password]"
11
+ puts " The verb is optional, if you leave it off you'll get an interactive shell."
12
+ puts " put and post both take the input body on stdin."
13
+ exit(1)
14
+ end
15
+
16
+ if %w(get put post delete).include? ARGV.first
17
+ @verb = ARGV.shift
18
+ else
19
+ @verb = nil
20
+ end
21
+
22
+ @url = ARGV.shift || 'http://localhost:4567'
23
+
24
+ config = YAML.load(File.read(ENV['HOME'] + "/.restclient")) rescue {}
25
+
26
+ @url, @username, @password = if c = config[@url]
27
+ [c['url'], c['username'], c['password']]
28
+ else
29
+ [@url, *ARGV]
30
+ end
31
+
32
+ usage("invalid url '#{@url}") unless @url =~ /^https?/
33
+ usage("too few args") unless ARGV.size < 3
34
+
35
+ def r
36
+ @r ||= RestClient::Resource.new(@url, @username, @password)
37
+ end
38
+
39
+ r # force rc to load
40
+
41
+ if @verb
42
+ begin
43
+ if %w(put post).include? @verb
44
+ puts r.send(@verb, STDIN.read)
45
+ else
46
+ puts r.send(@verb)
47
+ end
48
+ exit 0
49
+ rescue RestClient::Exception => e
50
+ puts e.response.body if e.respond_to? :response
51
+ raise
52
+ end
53
+ end
54
+
55
+ %w(get post put delete).each do |m|
56
+ eval <<-end_eval
57
+ def #{m}(path, *args, &b)
58
+ r[path].#{m}(*args, &b)
59
+ end
60
+ end_eval
61
+ end
62
+
63
+ def method_missing(s, *args, &b)
64
+ super unless r.respond_to?(s)
65
+ begin
66
+ r.send(s, *args, &b)
67
+ rescue RestClient::RequestFailed => e
68
+ print STDERR, e.response.body
69
+ raise e
70
+ end
71
+ end
72
+
73
+ require 'irb'
74
+ require 'irb/completion'
75
+
76
+ if File.exists? ".irbrc"
77
+ ENV['IRBRC'] = ".irbrc"
78
+ end
79
+
80
+ if File.exists?( File.expand_path(rcfile = "~/.restclientrc") )
81
+ load(rcfile)
82
+ end
83
+
84
+ ARGV.clear
85
+
86
+ IRB.start
87
+ exit!
@@ -0,0 +1,2 @@
1
+ # More logical way to require 'rest-client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,2 @@
1
+ # This file exists for backward compatbility with require 'rest_client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,165 @@
1
+ require 'uri'
2
+ require 'zlib'
3
+ require 'stringio'
4
+
5
+ begin
6
+ require 'net/https'
7
+ rescue LoadError => e
8
+ raise e unless RUBY_PLATFORM =~ /linux/
9
+ raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby"
10
+ end
11
+
12
+ require File.dirname(__FILE__) + '/restclient/exceptions'
13
+ require File.dirname(__FILE__) + '/restclient/request'
14
+ require File.dirname(__FILE__) + '/restclient/abstract_response'
15
+ require File.dirname(__FILE__) + '/restclient/response'
16
+ require File.dirname(__FILE__) + '/restclient/raw_response'
17
+ require File.dirname(__FILE__) + '/restclient/resource'
18
+ require File.dirname(__FILE__) + '/restclient/payload'
19
+ require File.dirname(__FILE__) + '/restclient/net_http_ext'
20
+
21
+ # This module's static methods are the entry point for using the REST client.
22
+ #
23
+ # # GET
24
+ # xml = RestClient.get 'http://example.com/resource'
25
+ # jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
26
+ #
27
+ # # authentication and SSL
28
+ # RestClient.get 'https://user:password@example.com/private/resource'
29
+ #
30
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
31
+ # RestClient.post 'http://example.com/resource', :param1 => 'one'
32
+ #
33
+ # # nest hash parameters
34
+ # RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
35
+ #
36
+ # # POST and PUT with raw payloads
37
+ # RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
38
+ # RestClient.post 'http://example.com/resource.xml', xml_doc
39
+ # RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
40
+ #
41
+ # # DELETE
42
+ # RestClient.delete 'http://example.com/resource'
43
+ #
44
+ # # retreive the response http code and headers
45
+ # res = RestClient.get 'http://example.com/some.jpg'
46
+ # res.code # => 200
47
+ # res.headers[:content_type] # => 'image/jpg'
48
+ #
49
+ # # HEAD
50
+ # RestClient.head('http://example.com').headers
51
+ #
52
+ # To use with a proxy, just set RestClient.proxy to the proper http proxy:
53
+ #
54
+ # RestClient.proxy = "http://proxy.example.com/"
55
+ #
56
+ # Or inherit the proxy from the environment:
57
+ #
58
+ # RestClient.proxy = ENV['http_proxy']
59
+ #
60
+ # For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
61
+ #
62
+ # >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
63
+ # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
64
+ #
65
+ module RestClient
66
+
67
+ def self.get(url, headers={}, &block)
68
+ Request.execute(:method => :get, :url => url, :headers => headers, &block)
69
+ end
70
+
71
+ def self.post(url, payload, headers={}, &block)
72
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
73
+ end
74
+
75
+ def self.put(url, payload, headers={}, &block)
76
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
77
+ end
78
+
79
+ def self.delete(url, headers={}, &block)
80
+ Request.execute(:method => :delete, :url => url, :headers => headers, &block)
81
+ end
82
+
83
+ def self.head(url, headers={}, &block)
84
+ Request.execute(:method => :head, :url => url, :headers => headers, &block)
85
+ end
86
+
87
+ def self.options(url, headers={}, &block)
88
+ Request.execute(:method => :options, :url => url, :headers => headers, &block)
89
+ end
90
+
91
+ class << self
92
+ attr_accessor :proxy
93
+ end
94
+
95
+ # Setup the log for RestClient calls.
96
+ # Value should be a logger but can can be stdout, stderr, or a filename.
97
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
98
+ def self.log= log
99
+ @@log = create_log log
100
+ end
101
+
102
+ def self.version
103
+ version_path = File.dirname(__FILE__) + "/../VERSION"
104
+ return File.read(version_path).chomp if File.file?(version_path)
105
+ "0.0.0"
106
+ end
107
+
108
+ # Create a log that respond to << like a logger
109
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
110
+ def self.create_log param
111
+ if param
112
+ if param.is_a? String
113
+ if param == 'stdout'
114
+ stdout_logger = Class.new do
115
+ def << obj
116
+ STDOUT.puts obj
117
+ end
118
+ end
119
+ stdout_logger.new
120
+ elsif param == 'stderr'
121
+ stderr_logger = Class.new do
122
+ def << obj
123
+ STDERR.puts obj
124
+ end
125
+ end
126
+ stderr_logger.new
127
+ else
128
+ file_logger = Class.new do
129
+ attr_writer :target_file
130
+
131
+ def << obj
132
+ File.open(@target_file, 'a') { |f| f.puts obj }
133
+ end
134
+ end
135
+ logger = file_logger.new
136
+ logger.target_file = param
137
+ logger
138
+ end
139
+ else
140
+ param
141
+ end
142
+ end
143
+ end
144
+
145
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
146
+
147
+ @@log = nil
148
+
149
+ def self.log # :nodoc:
150
+ @@env_log || @@log
151
+ end
152
+
153
+ @@before_execution_procs = []
154
+
155
+ # Add a Proc to be called before each request in executed.
156
+ # The proc parameters will be the http request and the request params.
157
+ def self.add_before_execution_proc &proc
158
+ @@before_execution_procs << proc
159
+ end
160
+
161
+ def self.before_execution_procs # :nodoc:
162
+ @@before_execution_procs
163
+ end
164
+
165
+ end