For the past couple of weeks I’ve been working on a minimal HTTP client library for Raku, and it has now been released. Say hello to HTTP::Tiny!
Initially, the project started as an excuse for me to learn about using Raku in the real world. After the project was chosen, a secondary goal was to learn about the HTTP protocol.1
That second part was not as courageous as you might think because, in case you are not coming from the Perl world, there is already a Perl library named HTTP::Tiny which I was going to use as a model. So rather than implementing the HTTP spec from scratch, the idea was to port an existing and well tested library.
The more I worked on it, however, the more I realised that this might actually be useful to have in the Raku world as well, and these are reflected in the abstract of the original Perl library, which I’ve inherited for the Raku one as well:
A small, simple, correct HTTP/1.1 client
The “small” in the abstract is related to the
::Tiny in the name, which comes
from an idea first proposed by Adam Kennedy for CPAN modules: to write
“tiny” versions of useful modules implemented in as little code as possible,
with “no non-core dependencies”.
This reference to a “core” makes more sense in Perl because that language has a clearly defined distribution of “core” modules that can be considered “part of the language”. It is not common, and indeed difficult, to have a working version of Perl that does not have the core modules installed.
And although Raku also has Rakudo Star, which works as a sort of de-facto core distribution, this is by no means a “core” set, but more a recommended set of modules to accomplish common tasks.
And this is important, because particularly when trying to bring Raku into environments where Raku is not already established, any external dependency is a barrier.
My challenge when writing the Raku version of HTTP::Tiny was to use only language built-ins. To write a minimal HTTP client that was usable, and had no dependencies.
As for “as little code as possible”, HTTP::Tiny has just over 1000 lines of code. Deciding if that’s too much is left as an exercise for the beholder.
Simplicity in software can be understood in a number of different ways, and some of them are related to the point above: the more code you use, the more complexity it hides. In that sense, HTTP::Tiny is as simple as I’ve been able to make it.
But a different way to understand “simple” is in the simplicity of use, which relates to the interface that is available for the user.
At its core, HTTP::Tiny has one method:
request. Every other method
available (with the exception of the
can-ssl utility one) calls this one
method to perform the core of its work. The signature is shown below:
method request ( Str $method, Str $url, :%headers, :$content, :&data-callback, :&trailer-callback, ) returns Hash
The only required parameters are the method and the URL, with the remaining ones existing to support the multiple different kinds of requests available.
Every effort was made to keep this interface small and predictable, but ultimately, whether this interface is simple or not will also be up to the users of this library. To see what this means, the documentation is probably the best place to check, and a cookbook-style document with examples of common requests is also available to see what common requests look like.
More importantly, HTTP::Tiny aims to be a correct implementation of the HTTP/1.1 transport, and to my surprise, this might be the area where this library might make the most significant contribution.
HTTP::Tiny of course supports the most common use cases, including form and file uploads. But it also supports streaming requests, multipart ranged responses, and both HTTP and HTTPS proxied connections. It also handles unexpected 1XX responses, request redirection, and trailers in chunked responses.2
Needless to say, it might strive for correctness, but it is far from perfect. A full list of known limitations is available in the documentation, and that list will undoubtedly grow to include the limitations that will only become apparent with use.
But for that it needs users, so please consider giving HTTP::Tiny a shot.
Yes, the P stands for “protocol” already. Thanks. ↩
Some of these things might seem obvious, but I found that support for all of them is unexpectedly hard to come by in the existing libraries. The ones that were easily resolved became upstream contributions (because we’re not competitors but colleagues), but not all of them have been resolved. ↩