Announcing Isahc 1.0 #282
sagebind
started this conversation in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Today I am pleased to announce the public release of version 1.0 of Isahc, an HTTP client for Rust! In this post I will go over some of the major changes and additions in depth. You can see a complete list of all the changes since the previous version on the release page.
Minimum supported Rust version
Declaring a Minimum Supported Rust Version (MSRV) is the practice of pinning a version of your library to a specific version of Rust that you will guarantee it will always compile with. This is simply good practice for stable libraries as it gives stability to downstream projects that need to use specific versions of Rust or prefer a slower upgrade cadence. Of course, you can always use a newer version than the MSRV if you so choose.
For Isahc 1.0, our MSRV is currently set to Rust 1.41, released January 2020. It was picked because it is the version currently distributed in Debian stable (a common third-party channel for Rust installation) and contains all of the major compiler features that Isahc strictly needs. It is somewhat unclear whether bumping the MSRV will require a major version bump or just a minor one, but at least we don't have to decide that yet!
Splitting sync and async responses
The most significant breaking change in 1.0 separates the response body and methods into distinct types and traits. The primary reason for this is to avoid some confusion that has occurred about which methods to use and when.
Previously, we had one
Body
type which was used for both sync and async requests and supported both sync and async I/O. In one sense this was convenient, but we began to see lots of confusion on which methods should be used in an async context. As the most common example seen, since the body provided both atext()
method and atext_async()
method, users would often be usingtext()
when inside an async function, not realizing thattext()
was blocking (it reads from the response stream and decodes the text incrementally) and that they should be usingtext_async()
instead. The end result would often be some performance issues caused by blocking in an async function.This was clearly a poor design on Isahc's part. Instead of having an API that guided the user towards the pit of success, we offered multiple methods with different behaviors that were easy to mix up and caused some undue frustration to some users.
To remedy this, we did what any good Rust API should do: leverage strong types and traits to let the compiler expose the right methods at the right time, and help the user make the right choice, every time. Instead of just one
Body
type, Isahc now also has anAsyncBody
type, which now houses all the async APIs previously provided byBody
. In addition, theResponseExt
trait that previously housed all our extension methods for responses has been split apart into three different traits:ResponseExt
: Contains all response methods that primarily interact with headers or other metadata. No methods interact with the response body, and is generic over any body type.ReadResponseExt
: Contains all response methods that directly interact with a synchronous response body.AsyncReadResponseExt
: Contains all response methods that directly interact with an asynchronous response body. All its methods returnFuture
s.All three traits are in the prelude module, so if you continue to import the prelude, then these methods will still be automatically available. Since the blocking and asynchronous methods are now mutually exclusive, we were able to drop the
_async
suffix from the asynchronous versions. So now all you have to write isto get the text of a webpage asynchronously, and
for the synchronous version. Using the same method names for both but having the compiler automatically select the right waiting model for you based on the initial call should improve the ergonomics greatly and help users fall into the pit of success.
As an additional benefit to this separation, you can now construct a
Body
from anything implementingRead
and send it as the body of aPOST
orPUT
request to do synchronous uploads. This previously was not possible because bodies must always be async to work with the async engine that executes all requests. Now that synchronous requests have their own body type, we can perform blocking reads inside the synchronous call itself and feed the bytes into an asynchronous channel for the engine to consume.Error type updates
Isahc's
Error
type has been refactored from a flat enum into an opaque struct with an associatedErrorKind
enum, modeled after the design used bystd::io::Error
. The new interface offers several benefits over the previous enum:#[non_exhaustive]
, making it possible to add new error kinds in the future without making breaking changes.Clone
even though the source error might not by using anArc
internally, which is helpful in certain circumstances. There is little runtime cost to this asArc
does not actually perform any atomic operations except on drop and if you actually clone it.Future work
While this release does mark the API as stable, there is still plenty of work yet to be done next year and beyond before Isahc will fully complete its vision.
Performance tuning
Isahc is reasonably fast in benchmarks today and is happily used in production by multiple users, but there is definitely room for improvement. Optimizing runtime performance will be a major focus in 2021. There are already a few known areas that will be addressed:
Stabilizing new APIs
There remain a few major APIs that Isahc still needs to deliver in order to provide a fully feature-complete experience for developers. One such feature is interceptors, which allows you to add custom middleware behavior to augment an HTTP client with new behaviors. This is already implemented partially in 1.0 and both cookie handling and redirect policies have been rewritten as interceptors, but the API is still behind an unstable feature flag for users. Once we're confident in the API shape we will make it available for everyone.
Another feature sorely missing is a high-level interface for sending URL-encoded and multipart forms. You can of course do this already by crafting a form body by hand or by using a third-party multipart library, but this is something that should really be available in Isahc proper.
Rustls support
Using Rustls as the TLS backend for HTTPS requests is one of Isahc's most highly requested features. This has been difficult to address, because TLS is currently handled by libcurl internally with no straightforward way of using custom backends.
The plan initially was to use a patched libcurl to add Rustls support, but this October ISRG announced that they will be adding official support for Rustls to curl. We're keeping a close eye on the progress of this development and will be sure to offer Rustls an opt-in feature once this becomes available in a new curl release. Implementation is already under way and we expect this to be ready in the first half of 2021.
Thanks
Isahc would not be where it is today if not for the many helpful people who submitted suggestions, ideas, and bug reports over the lifetime of the project. Special thanks as well to the contributors who submitted pull requests for the past couple years. We appreciate it!
Beta Was this translation helpful? Give feedback.
All reactions