-
Notifications
You must be signed in to change notification settings - Fork 621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BREAKING: feat(http): Request API & Middleware #1555
Conversation
…o middleware-experiment
I've validated this pattern with a couple of closed-source projects that currently use the bare net/http server, and it works very well. I'm excited by this change. |
@LionC |
I think the custom Isn't a similar thing possible with |
I'm concerned this is incompatible with how middleware works in Oak (cc @kitsonk) |
Oak's Middleware depends on oak specific concepts like Context, Application, etc. So I don't think it's reasonable to provide oak-compatible middleware in
|
Thanks for all the input. I will try to add my view:
What do you mean exactly with magical regarding the Regarding const handler =
log(
gzip(
cors("example.org",
authenticate(
authorize(
validate(someSchema)
)
)
)
)
) that does not feel optimal to me. Pretty much all middleware systems (Express, Koa / Oak, even ones in other languages) seem to use some form of API that reads like a sequence on one level, in the JS ones they all have
I personally do not see the learning curve but maybe I am misunderstanding - it is still perfectly fine and works no problem to just write a
We (I talked to @keithamus about this specific point a lot) thought about that - the problem is that adding another parameter every time we want to pass some new data to handlers that is not covered by the I think it would be really valuable to have one central place to access all information and functionality associated with one request that can be safely extended and that is easily discoverable (also via LSP).
I agree with @kt3k, from everything I have seen, I think oak could provide a function to convert this format into oak middleware. |
Updated to main, will fix updated tests soon (again^^) |
@LionC thank you for the PR, but I'm going to close it without a merge. This PR sparked conversation among the core team to support middlewares and we are still debating adding support for |
std/http
Request API and MiddlewareAfter delaying this again and again to polish it, here is a (evolved) review-ready version of POC in the linked issue #1295 .
Before I go into the ideas and changes here, I want to give some credit. Even though I wrote the code, I want to explicitly mention and thank:
Goals
std/http
API ergonomic and powerful enough to be a good starting point for actual applications at some point as well as offer smooth out of the box utilities fordeno deploy
HTTP casesreq => res
API offering all information needed regarding a specific requestChanges
I try to summarize the changes in the PR below, but I would highly encourage reading the docs - they are an important part of the module and should be good at explaining the concepts.
Add
Method
enum to theStatus
moduleAdds another enum with the HTTP methods which actually have a standardized representation, parallel to
Status
.HttpRequest
Delegate WrapperAdds an
HttpRequest
-class (got a better name? please say so!) that wraps aRequest
object, delegating to it (and thus implementing theRequest
API interface itself) and adding convenience methods and properties to have a unified API:connInfo
property, holding theconnInfo
that was passed separately beforeparsedUrl
property to access aURL
object for the request url (as a first start for convenience APIs)context
object to hold (initially empty) request context with an.addContext()
method to add onto itNote that there should probably be a lot more convenience methods here - like a (
CookieStore
compatible?) lazy cookie reading API, maybe a way to access parsed content types lazily etc - I just wanted to create a space where that is possible and clean up the API without bloating the PR too much.BREAKING:
Handler
SignatureThe
Handler
signature has been reduced to justreq: HttpRequest => Response
.This only breaks code that relies on the positional
connInfo
argument that was removed. Code that just depends on the request will continue to work, asHttpRequest implements Request
.This cleans up the API, creating a place to add more request information onto in
HttpRequest
instead of adding more parameters while also enabling the established middleware signature in the change below.Middleware
&chain()
Adds a
chain()
function that allows to chain(req: HttpRequest, next: Handler) => Response
middleware together with very little actual runtime code in a type safe, order aware manner. Chains can be arbitrarily nested, understand when they are terminated and will generally stop you from running into runtime errors.Terminated chains are actual
Handler
s and thus cann be passed toserve
:The actual runtime code of
chain()
is very small - types omitted, the wholemiddleware.ts
file is just:But the type safety and resulting DX is made possible by typing code around the
Middleware
type, which is the TS way to write middleware, enforcing middleware authors to be type safe. The typing code mostly constraints what one can do to provide maximum safety and instant LSP feedback.The typing code looks pretty big, which is mostly because TS does not have a good way to reuse type parameter sets (at least none that I know of).
README Docs
Adds a table of contents to the
README
, and a section about Middleware, while integrating the other changes and lightly touching up some of the other docs.Removes docs about the legacy server.
Try it out
Under
http/middleware/example_server.ts
you find a server using the middleware examples from the docs.