Skip to content

Commit

Permalink
added support for shortcut request methods
Browse files Browse the repository at this point in the history
  • Loading branch information
rubiii committed Sep 23, 2010
1 parent 906eb81 commit 676d6b7
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 45 deletions.
73 changes: 48 additions & 25 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,74 @@ The gem is available through {Rubygems}[http://rubygems.org/gems/httpi] and can

== Basic examples

Creating the most basic request object and executing an HTTP GET request:
Let's create the most basic request object and execute a GET request:

request = HTTPI::Request.new :url => "http://example.com"
HTTPI::Client.get request

The most basic HTTP POST request:
And a POST request with a request object:

request = HTTPI::Request.new
request.url = "http://post.example.com"
request.body = "send me"

HTTPI::Client.post request

An HTTP GET request using HTTP basic auth and the Curb adapter:
Or a GET request using HTTP basic auth and the Curb adapter:

request = HTTPI::Request.new
request.url = "http://auth.example.com"
request.basic_auth "username", "password"

HTTPI::Client.get request, :curb

HTTPI also comes with some shortcuts. This executes a GET request:

HTTPI::Client.get "http://example.com"

And here's a POST:

HTTPI::Client.post "http://example.com", "<some>xml</some>"

== HTTPI::Request

The HTTPI::Request serves as a common denominator of options that HTTPI adapters need to support. It represents an HTTP request and contains the following options:
The HTTPI::Request serves as a common denominator of options that HTTPI adapters need to support. It represents an HTTP request and lets you customize various settings:

* [url] the URL to access
* [proxy] the proxy server to use
* [headers] a Hash of HTTP headers
* [body] the HTTP request body
* [open_timeout] the open timeout (sec)
* [read_timeout] the read timeout (sec)

It also contains methods for setting up authentication:

* [basic_auth] HTTP basic auth credentials

* [url] the URL to access
* [proxy] the proxy server to use
* [headers] a Hash of HTTP headers
* [body] the HTTP request body
* [open_timeout] the open timeout (sec)
* [read_timeout] the read timeout (sec)
* [basic_auth] HTTP basic auth credentials
==== TODO:

Please note, that this list is far from complete and will be extended with further options.
* Add support for HTTP digest authentication
* Add support for SSL client authentication

== HTTPI::Client

The HTTPI::Client uses one of the available adapters to execute HTTP requests. It currently supports the following request methods:
The HTTPI::Client uses one of the available adapters to execute HTTP requests. It currently supports GET and POST requests:

=== GET

* get(request, adapter = nil)
* get(url, adapter = nil)

=== POST

* post(request, adapter = nil)
* post(url, body, adapter = nil)

You can specify the adapter to use per request. Request methods always returns an HTTPI::Response.

==== TODO:

You can specify the adapter to use per request. Every request method returns an HTTPI::Response.
* Add support for HEAD, PUT and DELETE requests

== HTTPI::Adapter

Expand All @@ -61,7 +86,7 @@ HTTPI uses adapters to support multiple HTTP libraries. It currently contains ad
* {httpclient}[http://rubygems.org/gems/httpclient] ~> 2.1.5
* {curb}[http://rubygems.org/gems/curb] ~> 0.7.8

By default, HTTPI uses the HTTPClient. Changing the default is fairly easy:
By default, HTTPI uses the HTTPClient. But changing the default is fairly easy:

HTTPI::Adapter.use = :curb

Expand All @@ -71,21 +96,19 @@ You can find a list of supported adapters via:

== HTTPI::Response

Every HTTPI::Client request method returns an HTTPI::Response containing the response code, headers and body.
As mentioned before, every request method return an HTTPI::Response. It contains the response code, headers and body.

response = HTTPI::Client.get request

response.code # => 200
response.headers # => { "Content-Encoding" => "gzip" }
response.body # => "<!DOCTYPE HTML PUBLIC ..."

== Participate

We appreciate any help and feedback, so please get in touch!
==== TODO

== TODO
* Return the original HTTPI::Request for debugging purposes
* Return the time it took to execute the request

Extend the HTTPI::Request to support:
== Participate

* HTTP digest authentication
* SSL client authentication
We appreciate any help and feedback, so please get in touch!
1 change: 0 additions & 1 deletion lib/httpi.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
require "httpi/version"
require "httpi/client"
require "httpi/request"
50 changes: 45 additions & 5 deletions lib/httpi/client.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,63 @@
require "httpi/request"
require "httpi/adapter"

module HTTPI
class Client
class << self

# Expects an <tt>HTTPI::Request</tt> and an optional +adapter+ to
# execute an HTTP GET request. Returns an <tt>HTTPI::Response</tt>.
# Executes an HTTP GET request and returns an <tt>HTTPI::Response</tt>.
#
# ==== Example
#
# Accepts an <tt>HTTPI::Request</tt> and an optional adapter:
#
# request = HTTPI::Request.new :url => "http://example.com"
# HTTPI::Client.get request, :httpclient
#
# ==== Shortcut
#
# You can also just pass a URL and an optional adapter if you don't
# need to configure the request:
#
# HTTPI::Client.get "http://example.com", :curb
def get(request, adapter = nil)
request = Request.new :url => request if request.kind_of? String
find_adapter(adapter).get request
end

# Expects an <tt>HTTPI::Request</tt> and an optional +adapter+ to
# execute an HTTP POST request. Returns an <tt>HTTPI::Response</tt>.
def post(request, adapter = nil)
# Executes an HTTP POST request and returns an <tt>HTTPI::Response</tt>.
#
# ==== Example
#
# Accepts an <tt>HTTPI::Request</tt> and an optional adapter:
#
# request = HTTPI::Request.new
# request.url = "http://example.com"
# request.body = "<some>xml</some>"
#
# HTTPI::Client.post request, :httpclient
#
# ==== Shortcut
#
# You can also just pass a URL, a request body and an optional adapter
# if you don't need to configure the request:
#
# HTTPI::Client.post "http://example.com", "<some>xml</some>", :curb
def post(*args)
request, adapter = extract_post_args(args)
find_adapter(adapter).post request
end

private

# Checks whether +args+ contains of an <tt>HTTPI::Request</tt> or a URL
# and a request body plus an optional adapter and returns an Array with
# an <tt>HTTPI::Request</tt> and (if given) an adapter.
def extract_post_args(args)
return args if args.first.kind_of? Request
[Request.new(:url => args[0], :body => args[1]), args[2]]
end

# Accepts an +adapter+ (defaults to <tt>Adapter.use</tt>) and returns
# a new instance of the adapter to use.
def find_adapter(adapter)
Expand Down
80 changes: 66 additions & 14 deletions spec/httpi/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,101 @@

describe HTTPI::Client do
let(:client) { HTTPI::Client }
let(:default_adapter) { HTTPI::Adapter.find HTTPI::Adapter.use }
let(:curb) { HTTPI::Adapter.find :curb }

describe ".get" do
describe ".get(request)" do
it "should execute an HTTP GET request using the default adapter" do
adapter = HTTPI::Adapter.find HTTPI::Adapter.use
request = HTTPI::Request.new
default_adapter.any_instance.expects(:get).with(request)

adapter.any_instance.expects(:get).with(request)
client.get request
end
end

describe ".get(request, adapter)" do
it "should execute an HTTP GET request using the given adapter" do
adapter = HTTPI::Adapter.find :curb
request = HTTPI::Request.new

adapter.any_instance.expects(:get).with(request)
curb.any_instance.expects(:get).with(request)

client.get request, :curb
end
end

describe ".get(url)" do
it "should execute an HTTP GET request using the default adapter" do
HTTPI::Request.any_instance.expects(:url=).with("http://example.com")
default_adapter.any_instance.expects(:get).with(instance_of(HTTPI::Request))

client.get "http://example.com"
end
end

describe ".get(url, adapter)" do
it "should execute an HTTP GET request using the given adapter" do
HTTPI::Request.any_instance.expects(:url=).with("http://example.com")
curb.any_instance.expects(:get).with(instance_of(HTTPI::Request))

client.get "http://example.com", :curb
end
end

describe ".get" do
it "should raise an ArgumentError in case of an invalid adapter" do
lambda { client.get HTTPI::Request.new, :invalid }.should raise_error(ArgumentError)
end
end

describe ".post" do
it "should raise an ArgumentError in case of an invalid URL" do
lambda { client.get "invalid" }.should raise_error(ArgumentError)
end
end

describe ".post(request)" do
it "should execute an HTTP POST request using the default adapter" do
adapter = HTTPI::Adapter.find HTTPI::Adapter.use
request = HTTPI::Request.new
default_adapter.any_instance.expects(:post).with(request)

adapter.any_instance.expects(:post).with(request)
client.post request
end
end

describe ".post(request, adapter)" do
it "should execute an HTTP POST request using the given adapter" do
adapter = HTTPI::Adapter.find :curb
request = HTTPI::Request.new

adapter.any_instance.expects(:post).with(request)
curb.any_instance.expects(:post).with(request)

client.post request, :curb
end
end

describe ".post(url, body)" do
it "should execute an HTTP POST request using the default adapter" do
HTTPI::Request.any_instance.expects(:url=).with("http://example.com")
HTTPI::Request.any_instance.expects(:body=).with("<some>xml</some>")
default_adapter.any_instance.expects(:post).with(instance_of(HTTPI::Request))

client.post "http://example.com", "<some>xml</some>"
end
end

describe ".post(url, body, adapter)" do
it "should execute an HTTP POST request using the given adapter" do
HTTPI::Request.any_instance.expects(:url=).with("http://example.com")
HTTPI::Request.any_instance.expects(:body=).with("<some>xml</some>")
curb.any_instance.expects(:post).with(instance_of(HTTPI::Request))

client.post "http://example.com", "<some>xml</some>", :curb
end
end

describe ".post" do
it "should raise an ArgumentError in case of an invalid adapter" do
lambda { client.post HTTPI::Request.new, :invalid }.should raise_error(ArgumentError)
end
end

it "should raise an ArgumentError in case of an invalid URL" do
lambda { client.post "invalid" }.should raise_error(ArgumentError)
end
end

end

0 comments on commit 676d6b7

Please sign in to comment.