Do you really need 2 different handler interfaces?
There is a long history of HTTP frameworks that have a uniform interface for both client and server, for a project that in embracing chaining and proxy of HTTP seems a bit crazy to force people to convert between incoming-handler and outgoing-handler when outgoing-handler could very easily do both.
Some examples of frameworks that have a uniform interface for both client and server
- fetch / Service Workers (nearly) - see Cloudflare workers, Bun serve for more uniform examples.
- Restlet Java
- UtterlyIdle Java
- HTTP4K Kotlin
- Finagle Scala
- Amp PHP
I'm sure there are a lot more.
Anyway why does this matter? It means for creating proxy you just pass the request directly from the server handler to the client handler and then return the response. For middleway it's just another handler, for filters just another handler, for testing in memory just use the server handler without the TCP wrapper.
Anyway I hope you will consider it, it would be shame for probably the most portable and highly important interface in HTTP to ignore one of the most powerful abstractions the decorator pattern and instead double the amount of work for everyone to convert back and forward between the two interfaces.
Hi! Speaking generally for the authors of this spec, we all agree that the two different handler interfaces (and different types for {incoming,outgoing}-{request,response,body} generally) is a tremendous amount of unwanted complexity. We have plans to overcome this when first class support for async (futures) is provided in the Component Model. So, hopefully this will be simplified in the 0.3 timeframe.
I can let @lukewagner give a much more detailed explanation when he returns from vacation, if you need it.
@danielbodart Have you taken a look at the 0.3.0 draft yet? It significantly reduces the amount of duplication. This would be a great time to contribute feedback and make it even better.
Draft 3 looks much simpler!
I assume the reason to have a "duplicate" error code instead of using the response status code, is around making this a very tight binary contract rather than HTTP status code which when going beyond the usual RFC defined ones are more of a defacto standard etc?
Again this is more curiosity, is there a reason why you decided to merge HTTP URI into request instead of keeping it as a separate structure? Seems pretty non standard if I'm honest and also precludes more general reuse of URI but also moves away from the core principals behind HTTP and REST with the separation of URI to identify the resource, the message (request/response) and the method. Personally I'd prefer it if the names exactly matched the RFC rather than half making up names
I assume the reason to have a "duplicate" error code instead of using the response status code, is around making this a very tight binary contract rather than HTTP status code which when going beyond the usual RFC defined ones are more of a defacto standard etc?
I wasn't involved in this part of the design, but I assume it's because HTTP status codes only cover cases where a response is received from the server, whereas outbound requests can fail in ways such that no such response is received (e.g. connection refused, timeouts, TLS handshake errors, connection closed prematurely, etc.)
Again this is more curiosity, is there a reason why you decided to merge HTTP URI into request instead of keeping it as a separate structure?
Again, I wasn't involved in this part of the design, but @lukewagner might have more context.
+1 to @dicej's answers and indeed I would love to get the point where we can have a single handler interface since it unlocks a lot of useful composition scenarios.
The big use case which currently requires the 2 incompatible interfaces in Preview 2 (but will be satisfiable with only 1 handler interface in Preview 3) is the ability for incoming-handler.handle to keep running after it returns its response. If we gave incoming-handler.handle the same function type as outgoing-handler.handle, we'd lose this ability, whereas if did the converse, we'd lose concurrency of outgoing requests. Without native concurrency support (in Preview 3), we're forced to compromise one way or another.
Again this is more curiosity, is there a reason why you decided to merge HTTP URI into request instead of keeping it as a separate structure?
This was discussed a bit early on and the thinking then was that we can always add a separate target-URI method to requests returning a handle to a URI resource. But this probably requires we go back to working on the wasi-url proposal (as a standalone interface defining a URI resource type that is used by wasi-http) which is a good idea, but additional work. But once we do that (say, in a Preview 3 timeframe), if we didn't want the primitive fields still directly on request, we could deprecate them.