Http 0.0.1 - talk to the web humanely

Http is on Github: https://github.com/tarcieri/http

Version 0.0.1 (codename “half-baked 0.0.1 release”) is now available
as a gem: gem install http

Some of you may have seen the Python “Requests” library on Hacker News
yesterday (which racked up nearly 300 points):
http://news.ycombinator.com/item?id=3094695

There have been various attempts to make such a library in Ruby,
perhaps most notably “httparty”. I busted out httparty at a job
interview and amazed my interviewer when it just seemed to do
everything automatically.
Http aims to provide the simplest, easiest to use experience for an
HTTP library ever.

How do you use it? Like this:

body = Http.get “https://github.com/tarcieri/http
body.is_a? String => true

DONE. No making URI objects. No setting use_ssl even though you passed
in a URI::HTTPS object. It Just Works.

You may have noticed I’ve been stylizing the project “Http” and
perhaps you find that annoying. Maybe you just want to write HTTP.
Fine! That works too.

How is this any different from httparty? Good question!

Http employs the notion of chaining (ala jQuery) to construct complex
requests. For example, if we were to do:

Http.get “https://github.com/tarcieri/http/commit/HEAD

we would get back an HTML page. What if we want a JSON response?
Github lets you tack “.json” onto the end of the URL to get the JSON
representation from a browser, but what HTTP would really prefer we do
is employ content negotiation by using the Accept header. We can add
an Accept header with the following:

Http.with_headers(:accept =>
“application/json”).get(“https://github.com/tarcieri/http/commit/HEAD”)

This can be shortened to the following:
Http.with(:accept =>
“application/json”).get(“https://github.com/tarcieri/http/commit/HEAD”)

#with is an alias for #with_headers. Http also provides a first class
way to specify the Accept header:

Http.accept(:json).get(“https://github.com/tarcieri/http/commit/HEAD”)

Best of all, if you have a JSON library loaded which defines
JSON.parse and the server sends you back a response with Content-Type:
application/json, Http will automatically parse the response for you:

Http.accept(:json).get(“https://github.com/tarcieri/http/commit/HEAD”)
=> {“commit”=>{“added”=>[“CHANGES.md”],
“parents”=>[{“id”=>“ef4764d0a2daae6081be3afe14d7efee0f1b5f91”}],
“author”=>{“name”=>“Tony A.”, “login”=>“tarcieri”,
“email”=>“[email protected]”},
“url”=>"/tarcieri/http/commit/17d8c9a4206952f0d5f59fb661cbdfe18afb6c61",
“id”=>“17d8c9a4206952f0d5f59fb661cbdfe18afb6c61”,
“committed_date”=>“2011-10-10T20:49:47-07:00”,
“authored_date”=>“2011-10-10T20:49:47-07:00”, “message”=>“Initial
changelog”, “tree”=>“a6fe5111cb33d6ac66c7055c3c348bb7aa7b08fc”,
“committer”=>{“name”=>“Tony A.”, “login”=>“tarcieri”,
“email”=>“[email protected]”}}}

Is chaining really the only difference from httparty? For now, yes,
but coming soon, it will include a Ragel parsers by Carl L. from
his Picard project.
Included will be HTTP request and response parsers, as well as a MIME
multipart parser generated from a Ragel state machine description.
Hooray, no more cgi_multipart_eof_fix! (although I suppose that’s an
already dated reference)

Miscellaneous Q&A:

Q: Is this just a client library or will it support servers?
A: I would like to support minimalistic server capabilities (think the
TCPServer concept applied to HTTP). There’s nothing for that right now
though, sorry

Q: Will it support streaming?
A: You damn well better believe it will support streaming. Even
Net::HTTP supported streaming.

Q: How do I get the response headers?
A: Right now you can’t because there aren’t any response objects.
There will be! Http.get accepts an options hash, and the default
option is :response => :parsed_body. Changing :response => :object
will give you a response object. This will be the default behavior for
HttpClient.get as well (Http provides a separate HttpClient clas for
when you want OOP instead of KISS)

Q: I don’t want you automatically parsing JSON! How do I get the
string response back?
A: The default Http.get :response setting is “:parsed_body”. The
following request will give you back the response as a string:

Http.accept(:json).get(“https://github.com/tarcieri/http/commit/HEAD”,
:response => :body)
=>
“{“commit”:{“added”:[“CHANGES.md”],“parents”:[{“id”:“ef4764d0a2daae6081be3afe14d7efee0f1b5f91”}],“author”:{“name”:“Tony
Arcieri”,“login”:“tarcieri”,“email”:“[email protected]”},“url”:”/tarcieri/http/commit/17d8c9a4206952f0d5f59fb661cbdfe18afb6c61",“id”:“17d8c9a4206952f0d5f59fb661cbdfe18afb6c61”,“committed_date”:“2011-10-10T20:49:47-07:00”,“authored_date”:“2011-10-10T20:49:47-07:00”,“message”:“Initial
changelog”,“tree”:“a6fe5111cb33d6ac66c7055c3c348bb7aa7b08fc”,“committer”:{“name”:“Tony
Arcieri”,“login”:“tarcieri”,“email”:“[email protected]”}}}"

Q: Why didn’t you use Zed’s parser from Mongrel(2)?
A: I’m launching this first as a client library, so Mongrel is the
wrong place to look for a response parser. Zed did write a HTTP
response parser as part of RFuzz, and really response parsers are
nearly the same thing as request parsers. I know Carl a bit better
than Zed at this point though, so I decided to base my work off of
his.

Q: Will it support Websockets?
A: I’m going to bypass the whole philosophical debate about whether
HTTP and Websockets belong together and just say: SURE! Soon…

Q: Will it work with EventMachine?
A: The vaporware parser APIs will be great for people building evented
web stuff using EventMachine, but unfortunately no, Http does not
natively support EventMachine.

Q: Can I make multiple concurrent requests without EventMachine?
A: Sure, I’d love to throw in support for concurrent HTTP requests
using a thread pool. Despite whatRaffi Krikorian says about Ruby, it
can do scatter/gather programming, and quite well!

Q: Y U NO work on Celluloid?
A: I’ll probably switch back to working on Celluloid soon, but in the
meantime Http is a step towards a larger goal: hooking Celluloid to
the web. I’ll be using Http as the basis of a web server which
dispatches incoming requests (and Websockets) to Celluloid::Actors.

This looks awesome, thanks Tony!

On Mon, Oct 10, 2011 at 11:47 PM, Tony A.
[email protected]wrote:

Q: How do I get the response headers?
A: Right now you can’t because there aren’t any response objects.
There will be! Http.get accepts an options hash, and the default
option is :response => :parsed_body. Changing :response => :object
will give you a response object. This will be the default behavior for
HttpClient.get as well (Http provides a separate HttpClient clas for
when you want OOP instead of KISS)

This would be a necessary feature for most of my use cases.

Mea culpa, this is the 0.0.1 half-baked release :slight_smile:

Tony A. wrote:

Http is on Github: https://github.com/tarcieri/http

Version 0.0.1 (codename “half-baked 0.0.1 release”) is now available
as a gem: gem install http

Wow, bold choice for a gem name there :). Can’t believe this wasn’t
already taken.

Cheers,
Robin S.

Feel free to substitute “rest-client” for “httparty” in the initial
description I gave and the differences I call out will still hold true
:slight_smile:

2011/10/11 Bartosz Dziewoński [email protected]:

What about the rest-client gem? Isn’t this mostly the same?

2011/10/11, Robin S. [email protected]:

Someone else contacted me off-list about rest-client, so let me say
this:

Http’s goal is to be a unified client and server library complete with
Ragel parsers and unified Http::Request and Http::Response objects for
both server and client. At the same time I want to give it an awesome
API. But in some ways the API is almost secondary to the way it’s
being constructed, even if the API is the main thing I’ve been selling
it with right now.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs