-
Notifications
You must be signed in to change notification settings - Fork 2
Description
I think we need a "minimal" variant of makeDefaultOptions (the way to create new options from a library, when you don't know which concrete HTTP client implementation you're using). Because as a library, you can't afford to have the client arbitrarily choose to enable various features you're a) not aware of and b) aren't expecting. For example, if there's a "Batching" feature, represented by a protocol like:
protocol BatchingOptions: RequestOptions {
/// Defines the batch of body bytes that are filled up before being sent.
var batchSize: Int64?
}This could be a useful optimization, but always needs to be opt-in. Either by you using a known concrete client, or you requesting that feature through the protocol constraint:
func makeAnHTTPCall<Client: HTTPClient>(client: Client) where Client.RequestOptions: BatchingOptions async throws {
var options = client.makeDefaultOptions()
options.batchSize = 4096
try await client.perform(request, options: options) {
}
}However, if you don't request it, and your library looks like this:
func makeAnHTTPCall<Client: HTTPClient>(client: Client) async throws {
var options = client.makeDefaultOptions()
try await client.perform(request, options: options) {
}
}Then client.makeDefaultOptions() absolutely must have batchSize = nil, otherwise the library won't work correctly with bidi streaming, as bytes will be held back until reaching the batch size, but the library has no way of learning or fixing that, without explicitly requiring that feature just to turn it off.
So if we assume that the set of options protocols will be open, and community libraries will be able to add additional ones, and the set of HTTP client implementations will also be an open set, it means that "default options" must mean "features disabled", and libraries will only enable those that they need by explicitly requesting that protocol and enabling them.
Now, some features are on/off, such as this batching example, and we can easily require that "default options" turns it off. However for other features that can't really negatively affect a library's observable behavior, we can still discuss what "on" vs "off" means. For example, I'd argue it's fine if the default value for "HTTP versions supported" is "all", even though some folks could consider that "on". Maybe that means we should re-spell that feature as "Subset of HTTP versions requested", so not allowing an HTTP version would be considered "on" for that feature.
This is why I think we need another variant of "default options" that makes it clear that it's not "nice-to-have, recommended options" (which is useful for applications, and can still exist e.g. under the name "recommended"), but must be "all features as disabled as they can be" (which is the only way to make behavior predictable to libraries, here called "minimal").
Maybe the simplest spelling that still allows this is:
protocol HTTPClient {
// associated types
func makeRecommendedOptions() -> RequestOptions
func makeMinimalOptions() -> RequestOptions
// perform method
}
So applications and concrete client utils would default to recommended, while libraries would always start with minimal (though I don't like the name, so please suggest a better one).