Find file
Fetching contributors…
Cannot retrieve contributors at this time
219 lines (142 sloc) 7.47 KB


Weary is a tiny DSL for making the consumption of RESTful web services simple. It has evolved from the ideas put forth by libraries like HTTParty and Typhoeus. It provides some sweet syntactic sugar over the Net/HTTP standard library.

What does it do:

  • Quickly build an interface to your favorite REST API.
  • Parse XML and JSON with the Crack library.
  • Authentication with Basic Authentication and OAuth.
  • Asynchronous, multi-threaded requests.

RDoc | Gem | Wiki | Metrics



gem install weary

If you're interested in doing development on Weary, clone the repository and run bundle install to get the development dependencies.

Quick Start

class TwitterUser < Weary::Base
	domain ""
	get "show" do |resource|
		resource.with = [:id, :user_id, :screen_name]

user =
me = => "markwunsch").perform
puts me["name"]

Hey, that's me!

The Base API/DSL

Create a class that inherits from Weary::Base to give it methods to craft a resource request:

class Foo < Weary::Base
	declare "foo" do |resource|
		resource.url = "http://path/to/foo"

If you instantiate this class, you'll get an instance method named foo that crafts a GET request to "http://path/to/foo"

Besides the name of the resource, you can also give declare a block like:

declare "foo" do |r|
	r.url = "path/to/foo"
	r.via = :post 							# defaults to :get
	r.requires = [:id, :bar] 				# an array of params that the resource requires to be in the query/body
	r.with = [:blah]						# an array of params that you can optionally send to the resource
	r.authenticates = false					# does the method require authentication? defaults to false
	r.follows = false						# if this is set to false, the formed request will not follow redirects.
	r.headers = {'Accept' => 'text/html'}	# send custom headers. defaults to nil.

So this would form a method:

x = :id => "mwunsch", :bar => 123

That method would return a Weary::Request object. Use the perform method and get a Weary::Response that you could parse and/or examine.

Parsing the Body

Once you make your request with the fancy method that Weary created for you, you can do stuff with what it returns...which could be a good reason you're using Weary in the first place. Let's look at the above example:

x =
y = => "mwunsch", :bar => 123).perform.parse

Weary parses with Crack, but you're not beholden to it. You can get the raw Request body to have your way with:

x =
y = => "mwunsch", :bar => 123).perform

note: Weary used to have Nokogiri built in, using the #search method, but that was dropped.


Of course, you don't always have to use declare; that is a little too ambiguous. You can also use get, post, delete, etc. Those do the obvious.

Forming URLs

There are many ways to form URLs in Weary. You can define URLs for the entire class by typing:

class Foo < Weary::Base
	domain ""
	format :xml
	get "show_users"

If you don't supply a url when declaring the Resource, Weary will look to see if you've defined a domain, and will make a url for you. The above get declaration creates a url that looks like: I think it's better to write the whole URL out. That's unambiguous.

Weary DSL

You can create some defaults for all of our resources easily:

class Foo < Weary::Base

	def initialize(username,password)
		self.credentials username,password	#basic authentication
		self.defaults = {:user => username}	#parameters that will be passed in every request	 

	domain ""
	format :xml
	headers {'Accept' => 'text/html'}	# set headers
	post "update" {|r| r.authenticates = true}	# uses the defaults defined above!			

Then you can do something like this:

f ='me','secretz')

Which will create a POST Request for that will authenticate you, using basic authentication, with the username/password of "me"/"secrets" and will send the parameter {:user => "me"}. Easy.

Weary Class Methods

Maybe you don't want the baggage that comes with Weary::Base. That's okay, Weary provides some basic class-level methods to Easily build a Weary::Request:

# See examples/repo.rb to see this in practice
class Repository

  def show(user, repo)
    Weary.get "{user}/#{repo}"

end 'mwunsch', 'weary'

That will build the Get request to fetch the YAML info about this repository.

Pass a block to Weary.get to dive further into the Request:

Weary.get "" do |req|
	req.follows = false
	req.with = {:id => 'markwunsch'}
	req.credentials = {:username => 'markwunsch', :password => 'secret'}
	req.headers = {"User-Agent" => Weary::UserAgents["Safari 4.0.2 - Mac"]}

Request Callbacks

A Weary::Request has a couple of callbacks you can do:

status = Weary.get("") do |r|
	r.with = {:id => 'markwunsch'}

status.before_send do |request|
	puts "Sending a request to #{request.uri}"

status.on_complete do |response|
	if response.success?
		puts response.body
		puts "Something went wrong: #{response.code}: #{response.message}"

before_send is sent just before the request is made, and on_complete is triggered immediately following. before_send passes the Request object to the block and on_complete passes the Response object.

You don't need to define on_complete, though. Passing a block to the perform method of the Request also defines this callback or will overwrite what you had previously defined:

status.perform do |response|
	puts "Request to #{response.url}, complete. Got a #{response.code}."

Multiple Asynchronous Requests with Batch

Requests, along with the perform method, also has a perform! method, which spins off a Thread to actually perform the Net::HTTP Request. This method returns a Thread object, and is encapsulated by the perform method.

Weary::Batch allows you to make a group of perform! requests, firing at will. It takes a group of Requests.

# see examples/batch.rb
resources = %w[]
requests = []

## build the group of requests:
resources.each do |url|
	requests << Weary.get(url) do |req|
		req.on_complete {|res| puts "Hello from #{res.url}"}

## And fire them off:

Batch has callbacks, just like the Request:

Weary.batch(requests).perform do
	puts 'All done.'

You can investigate the pool of threads once you've called perform with Batch#pool or look at all the returned responses with Batch#responses.

And more...

There's more to discover in the Wiki.