Weary, the Ruby framework for making web service clients, got a late-night version bump.

What’s new in this version?

  • Adapters for Typhoeus and Excon.
  • Updated dependencies on multi-json and addressable
  • Response#parse can now take a block for custom Response body parsing.
  • Requestable module to allow for configuration that cascades from Client -> Resource -> Request
  • Issue #21 - now, Rack::Lint is run as part of the specs.

The code is cleaned up a bit as well, and is now getting all A’s on Code Climate.

Along with this new version of Weary, a new version of the Ruby bindings to the Gilt public API has been released: 0.2.0 with support for product categories.

gem install weary and make a thing.

Great question in GitHub issues, I hope this helps others:

I’m curious about how asynchronicity is implemented compared to Typhoeus.

When you call Request#perform, that computation is performed independently of the main program flow. This action is always non-blocking. Consider this example:

require 'weary/request'

request = Weary::Request.new "https://api.github.com/repos/mwunsch/weary"

request.perform do |response|
  puts response.body
end

Remember that perform takes a block that accepts a response and executes once the response has completed. When you execute this file as is you will not see the response’s body. Why? Because the main thread completes before the request has completed. Changing this to

require 'weary/request'

request = Weary::Request.new "https://api.github.com/repos/mwunsch/weary"

response = request.perform
puts response.body

will produce the desired results, and here’s why: Request#perform returns a Future — a lightweight proxy object wrapping the Response (Weary uses the promise gem under the hood). The main thread is only blocked when you call a method on the response. This is all done with plain ol’ Ruby Threads (of which there is a lot of FUD in the Ruby community because of the GIL, but this is a perfect use case for them).

I haven’t investigated Typhoeus's source code too deeply, but I believe it implements concurrency using an extension to libcurl-multi. Not sure what that means in practice compared to using a Thread.

Unlike Typhoeous, Weary does not provide a queue mechanism. But you could just do something like:

responses = [req1, req2].map(&:perform)

It might be helpful to look at how my Gilt gem performs multiple requests in parallel to get a sale’s products.

Also unlike Typhoueus, Weary provides no internal mechanisms for memoization or caching, but you can use Rack middleware to achieve the desired result. Hope that answers your question.

3 years ago, according to GitHub, I began my first substantial project written in the Ruby programming language: Weary. Weary is the thing driving tumblr-rb, and what allowed me to write it so quickly. Weary was the solution to a desire of mine to be able to quickly bootstrap and describe client libraries to RESTful web service API’s.

In the Spring of 2010, I announced my intention to rewrite it. Better late than never?

Today, Weary’s master branch reflects a complete rewrite from the ground up. As I prepare for the first release candidate of Weary 1.0, I want to take this time to document some intentions and invite your contributions and suggestions.

Consider the following Ruby code:

class GitHubClient < Weary::Client
  domain "https://api.github.com"

  get :list, "/user/repos" do |r|
    r.basic_auth!
  end

  post :create "/user/repos" do |r|
    r.basic_auth!
  end

  get :user, "/users/{user}/repos"

  get :repo, "/repos/{user}/{repo}"

  patch :edit, "/repos/{user}/{repo}" do |r|
    r.basic_auth!
  end
end

This is a pretty good sample of the Weary framework and DSL. This builds a client to a subset of the GitHub v3 api. Moving further with the class:

client = GitHubClient.new
client.list :username => "mwunsch", :password => "my-secret-password"
# -> returns a Weary::Request object

Every request has a #perform method that is asynchronous, and only blocks when accessed (it returns a future). You can pass a callback:

client.list(:username => "mwunsch", :password => "my-secret-password").perform do |response|
  puts response.body if response.success?
end

A new feature is the ability to have dynamic URL’s (using Addressable::Template):

client.user :user => "mwunsch"

But one of the things that makes this new version of Weary very powerful is that Rack is integrated deeply throughout the library. Every class that inherits from Weary::Client is a valid Rack application1. Which means you can do something like this:

# in a file called config.ru
run GitHubClient

rackup

curl "http://localhost:9292/repos/mwunsch/weary"

This means it’s really trivial to build specialized proxies to web service API’s and mount them anywhere you’d like (say, inside your Rails application).

Weary allows you to quickly build clients that take advantage of the full spectrum of the Rack ecosystem.

There’s a few more tasks to work on before getting a release candidate out, but as soon as that happens I’ll begin the work of migrating the Tumblr gem to use it.

There’s a lot more to this new version of Weary than I outlined here, so I invite you to dig into the code, fork it, and build some great things.


  1. For those newer to Ruby, Rack provides a standard interface for a web server to communicate with a Ruby application. 

Weary: The Road to 1.0

In the coming weeks, I plan on blocking out time to focus on Weary, my original Ruby pet project. Weary is the little REST consumer that powers the Tumblr Gem. I’ve written about Weary before. I have neglected it a bit since the release of tumblr-rb, but I’ve got a lot planned to get Weary to a 1.0 release. Here is what needs to be in Weary before it can reach that level:

1. Dynamic URL’s.

This is what your basic Weary Resource call looks like, taken from Tumblr::Writer:

post :delete do |del|
    del.url = 'http://www.tumblr.com/api/delete'
    del.requires = [:email, :password, :'post-id']
end

When you instantiate Tumblr::Writer that object now gets a method called delete:

write = Tumblr::Writer.new
write.delete :email => "test@testymcgee.com", :password => "s3cret", :'post-id' => 1234

Above, in the Resource declaration, it says that the keys :email, :password, and :'post-id' are required. When you call the delete method, if you do not provide a Hash containing all of the required keys as an argument, it will raise an exception.

The problem comes when there is a parameter that is not sent as an HTTP POST body or GET query, but as a segment of the URL. Such is the case with Tumblr’s Authenticated Reads. For a read, you must provide the username in the host of the url: http://#{username}.tumblr.com/api/read/.

The way I’ve handled this is by creating a method that falls back to Weary’s module methods:

def self.read(username, via = :get, params = {})
  Weary.request("http://#{username}.tumblr.com/api/read/", via) do |req|
    req.with = params unless params.blank?
  end
end

This is not optimal, and makes these methods an outlier from the preferred Weary way of doing things. Weary will handle this in a future release using the Addressable gem. Wynn has been toying with this a bit, but it has yet to be merged in.

post :authenticated_read do |r|
    r.url = "http://{username}.tumblr.com/api/read/"
    r.with = [:start,:num,:type,:id,:filter,:tagged,:search,:state]
    r.requires = [:email, :password]
end

Along with the required :email and :password keys, the Resource declaration says that a new key is required: :username, that builds the URL for the request.

reader = Tumblr::Reader.new
reader.authenticated_read :email => "test@testymcgee.com", :password => "s3cret", :username => "mwunsch"

2. Defaults at the Resource level.

Right now, it’s easy to save default key-value pairs that get sent with every request. It’s how the Tumblr Gem does a lot of its mojo. But maybe you want to have some default pairs that get sent with every resource, defined at the Class level. Weary will add a new defaults method to Resources.

post :dashboard do |dashboard|
    dashboard.url = "http://www.tumblr.com/api/dashboard"
    dashboard.requires = [:email,:password]
    dashboard.with = [:start,:num,:type,:filter,:likes]
    dashboard.defaults = {:num => 50, :likes = 1}
end

3. HTTP Connection Adapters

This is the new feature I am most excited about. Right now Weary::Request and Weary::Resource is a thin layer of syntactic sugar that sits above the standard Net::HTTP library. I’ll be working on abstracting away Net::HTTP into a Weary::Adapter class. When triggering Request#perform, it will defer to the adapter for how to form and make the Request. The Request and Resource classes will truly be abstract, and this allows us to build adapters for different HTTP libraries. So imagine doing something like this:

class Reader < Weary::Base
    adapter :typhoeus
end

I’ll be working hard on defining an API for creating Adapters. Weary will default to the Net::HTTP adapter, and will come with a Typhoeus adapter. This is similar to how Faraday does it’s magic, but with the sickly sweet Weary API we’ve all come to know and love.

4. Self-documenting

This has been an intended feature of Weary for a long time, and it will be a part of moving to 1.0. Weary will hook into the YARD documentation tool, and when defining a Resource, it will generate documentation. So not only can you create a Ruby library for your API, by creating the library you are also writing documentation for your API.

Keep an eye on Weary for the next month or so as these features trickle in, inching closer to 1.0.

The Tumblr Gem

Last night, I released the Tumblr gem, a command line utility and Ruby library for interacting with Tumblr. Here’s what it does:

$ tumblr my_post.txt

That will publish my_post.txt to Tumblr. Simple.

You can also give it a URL:

$ tumblr http://mwunsch.github.com/tumblr/tumblr.1.html

That will create a Link post on Tumblr pointing to the tumblr manpage.

Or create a Video post by giving it a YouTube or Vimeo URL:

$ tumblr http://www.youtube.com/watch?v=CW0DUg63lqU

Easy publishing to Tumblr on the command line.

Get Started

You need Ruby and Rubygems installed:

$ gem install tumblr-rb 

Read through tumblr(1) to get an idea of what you can do.

How it works

tumblr does a pretty good job of inferring what kind of post you want to make, as shown above, but you can add more options to your document by adding a little bit of YAML frontmatter, in the style of Jekyll. You can do things like specify a post-type, tagging posts, saving posts to your queue, etc. Read more about post formatting in tumblr(5).

Why?

Most of my Tumblr posts begin life as little notes in Notational Velocity (combined with Simplenote). I write them in Markdown, and then copy and paste them into Tumblr.com. It feels tedious. Now, with tumblr, I write a post in TextMate and can publish it immediately, with very little effort.

This post began life as a gist, and was published via the command line with tumblr.

The Tumblr gem was created as a kind-of-sort-of proof-of-concept for Weary, a Ruby library I wrote for simple RESTful web service consumption. Tumblr (the gem), is a robust Ruby wrapper supporting full coverage of the Tumblr API. The tumblr command line tool is a client of the Tumblr Ruby library (and comes packaged with it). I published this post with tumblr. In software, this is called "eating your own dogfood".

The Tumblr Gem (my more-or-less official name for it; I also sometimes refer to it as “tumblr-rb”), is Open Source, available under an MIT License. The source code is available on GitHub.

Follow me on Twitter @markwunsch and on Tumblr for updates on all of my Open Source projects.