I initially was pushing for the triple protocol myself but I'm not sure I really think it buys us anything unless we could help adopters only return documented responses, which we can't.
The crux of the issue is that we generated throwing protocol requirements for each of the documented API operations, which means adopter handlers can just throw whatever they choose.
As an aside: if we wanted to redesign this with even more type safety we could have generated non-throwing requirements, which would force users to return a value of type Operations.<OperationName>.Output
—i.e. a documented response, or explicitly reach for .undocumented(...)
.
It's possible we could also leverage the power of typed-throws to allow handlers to only throw documented errors, but that would have a whole bunch of design questions that would need answering.
In any event, both of these would be API breaking at this point so we need to accept where we are: adopter handlers can throw.
One could adopt a principled view here: if the handlers have thrown an error, it's likely to be an internal error, otherwise they could have returned a documented response. But, as this proposal highlights, folks are using errors for a convenience—where they will have to take responsibility for the response.
At that point, I no longer see value in us trying to police the response.
Furthermore, I think our existing approach of using the HTTP 500 response code when the handler has thrown is entirely defensible.
So I'm starting to warm to the idea that adopters might want to use this as a debugging mechanism, rather than a layer to try and rescue the error and reform a documented response.
In that scenario, I could see myself wanting to use my own personal header in debug builds to capture the underlying error, but happy to take whatever OpenAPIRuntime thought was appropriate for the response code and body. Others might prefer to use a free-form JSON in the body, but leave the response code and headers to whatever OpenAPIRuntime would have returned for an uncaught error.
So, in summary, I've cooled off on policing an incremental specificity to what folks provide and I'm sympathetic to providing an API that's easy to discover.
I think we have a few options for the protocol(s):
- Three layered protocols, non-optional requirements: this is the current proposal.
- One protocol, three non-optional requirements with default implementations: override what you want, and it's clear what the rest will be in the API surface.
- One protocol, three optional requirements: override what you want but OpenAPIRuntime is opaque about the rest of the request.
- One protocol with three non-optional requirements: you wanna provide a custom response, provide all the bits.
If we see this proposal as an escape-hatch, where we're allowing adopters to do custom logic and take full responsibility for whether they follow the OpenAPI document or not, then I think (4) might be clearest, possibly (2).