-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
feat: introduce middleware based sequence for REST #5366
Conversation
927c328
to
c48f1fd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raymondfeng looks like we are on a roll for adding middleware features :-)
const params: OperationArgs = await ctx.get( | ||
RestBindings.Operation.PARAMS, | ||
); | ||
return this.invokeMethod(route, params); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is next
not called here ? for this to be an independent middleware function, it should have no knowledge that it is the last in the middleware chain. The invocation part should handle that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the middleware logic's decision not to call next
as invokeMethod
returns the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I see; so next() is just a customary function for the middleware, it does not really link with the next middleware function in the chain ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that is why sequence.handle() is forced to invoke the middleware functions one by one ?
for (const opt of this.options) {
// Invoke registered Express middleware
debug(
'Invoking middleware chain %s with groups %s',
opt.chain,
opt.orderedGroups,
);
const done = await this.invokeMiddleware(context, opt);
if (done) break;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I see; so next() is just a customary function for the middleware, it does not really link with the next middleware function in the chain ?
It does. But it's up the middleware logic to decide if the next one should be invoked. The invokeMethod
is designed to invoke the controller method directly.
why sequence.handle() is forced to invoke the middleware functions one by one?
This is to allow multiple chains to be used one by one. If you need to cascade them, add the chain as a middleware or flatten the chains.
c57d182
to
37525e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A big -1 from me.
The current Sequence implementation is easy to understand (because it's based on await
flow control) and extend. The new proposal is introducing a lot of hidden complexity and behavior that looks like auto-magic to me.
I am willing to consider withdrawing my rejection if there is detailed and clear explanation for:
- what problems in the current Sequence design are you trying to solve by this pull request
- why these problems cannot be solved within the current design
- how can application developers modify the sequence in the new middleware style
- what is the migration path for existing applications
If we want to go all-in on middleware, then it may be better move away from Sequence entirely and use pure middleware-based composition of request handling flow.
@bajtos I know you might reject the PR :-). Yes, I would like to move to a middleware based pipeline by composition. The sequence can stay as the integration point to the application and it can facilitate the transition too. Here are a few thoughts that drive me to come up this PR:
|
37525e5
to
9463ac2
Compare
eb5563e
to
4aa9c3f
Compare
06ccea9
to
d3303ac
Compare
Here is another reason to unify all actions as middleware - #5562 (comment) |
d3303ac
to
2b382d6
Compare
16102e5
to
b72ba01
Compare
export class MiddlewareSequence implements SequenceHandler { | ||
static defaultOptions: InvokeMiddlewareOptions = { | ||
chain: RestTags.REST_MIDDLEWARE_CHAIN, | ||
orderedGroups: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this named orderedGroups
? Do sendResponse
, cors
, apiSpec
etc., resolve to arrays of middleware? If not, the name is misleading. If yes, the fact has to be clearly documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After going through the codebase, it has become clear to me. A name like executionOrder
or something like that might make it more obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We inherit orderedGroups
from interceptors - middleware is a specialized interceptors that are invoked as part of the sequence.
asMiddleware({ | ||
group: 'parseParams', | ||
upstreamGroups: 'findRoute', | ||
chain: RestTags.REST_MIDDLEWARE_CHAIN, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parseParams
, findRoute
and other strings are being repeated, I think we should be using constants.
packages/rest/src/sequence.ts
Outdated
'findRoute', | ||
|
||
// authentication | ||
'authentication', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this to work, user has to create a Provider<Middleware>
and set its group
value to authentication
; and many such authentication middleware can be added and anyone of them can cause the authentication to fail, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A group can have 0-N middleware and its name does not have semantic meaning. It's only for ordering purpose.
09a89b5
to
17d8980
Compare
@hacksparrow Thank you for the feedback. I believe that I have addressed your comments. PTAL. |
What purpose does this serve:
if we still have to do this?
I can understand for middleware not in the ordered group, but for those in the group - shouldn't they "know" it? And what happens if there is a conflict:
? I think we should add tests for the expected behavior. |
@hacksparrow The final order of middleware is settled using both the The I'll try to add some tests. |
17d8980
to
d2e60b2
Compare
d2e60b2
to
951408a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great effort! I followed the docs and reviewed the updated auth modules, don't see obvious problems.
This PR adds a middleware based sequence and wrap existing actions as middleware.
Checklist
👉 Read and sign the CLA (Contributor License Agreement) 👈
npm test
passes on your machinepackages/cli
were updatedexamples/*
were updated👉 Check out how to submit a PR 👈