-
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(cli): add lb4 interceptor
to generate interceptors and a booter to load interceptors
#2907
Conversation
58bc610
to
d6308c0
Compare
lb4 interceptor
to generate global interceptors and a booter to load global interceptors
16bdb94
to
e74c2f1
Compare
6280b9b
to
da707f3
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.
Nice addition.
I see two problematic parts:
- I consider anonymous functions in Providers as a bad practice, let's use named class methods instead.
- I'd like us to consider non-global interceptors too and find a design that can accommodate both global and non-global interceptors. Ideally, I'd like the CLI prompt to ask the developer whether they want to register the interceptor-being-created as a global one.
packages/boot/src/__tests__/integration/interceptor.booter.integration.ts
Outdated
Show resolved
Hide resolved
name: 'group', | ||
// capitalization | ||
message: utils.toClassName(this.artifactInfo.type) + ' group:', | ||
default: '', |
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.
How can the person running lb4 interceptor
find out what are the valid group names?
What happens when they enter a group name that's not recognized by the app?
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.
Based on our design, unknown group is sorted by alphabetical order before the known groups.
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.
Based on our design, unknown group is sorted by alphabetical order before the known groups.
That answered my second question 👍
The first one is still not answered though:
How can the person running
lb4 interceptor
find out what are the valid group names?
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.
Since the valid group names are configured by a binding, I'm not sure how we can check. Maybe we can improve the prompt to explain so.
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.
Maybe we can improve the prompt to explain so.
Sounds good.
Ideally, I'd like the prompt to tell me:
- What are the usual (default) group names
- Where can I find the actual list of group names as recognized by my application
packages/cli/generators/interceptor/templates/interceptor-template.ts.ejs
Outdated
Show resolved
Hide resolved
binding.tag(ContextTags.GLOBAL_INTERCEPTOR); | ||
binding | ||
.tag(ContextTags.GLOBAL_INTERCEPTOR) | ||
.tag({[ContextTags.NAMESPACE]: GLOBAL_INTERCEPTOR_NAMESPACE}); |
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.
I am confused. Why do we need both GLOBAL_INTERCEPTOR
tag and GLOBAL_INTERCEPTOR_NAMESPACE
? I mean why is it not enough to use the tag only?
Is it a good idea to use the same namespace for all interceptors, regardless of which component/extension is contributing them? Wouldn't it better to use namespaces similarly to how Java treat packages, i.e. interceptors contributed by @loopback/authorization
package should use @loopback/authorization
namespace.
Let's discuss.
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.
Only GLOBAL_INTERCEPTOR
is required. GLOBAL_INTERCEPTOR_NAMESPACE
is to make the binding key more readable.
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.
Please add a code comment to capture this information.
Also, what is your opinion about using the same namespace for all interceptors vs. using a namespace based on the component/extension contributing the interceptor?
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.
Personally, I prefer to use globalInterceptors.*
.
8cf4fb0
to
8ec48b8
Compare
Both are addressed. |
lb4 interceptor
to generate global interceptors and a booter to load global interceptorslb4 interceptor
to generate interceptors and a booter to load interceptors
7bb2c8a
to
5fb119b
Compare
5fb119b
to
4b3b1b4
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.
Looks mostly good at high level, let's do one more iteration to improve details and UX.
docs/site/Interceptor-generator.md
Outdated
command. If provided, the tool will use that as the default when it prompts for | ||
the name. | ||
|
||
`--global` - Optional flag to indicate a global interceptor (default to `true`) |
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.
If the flag is true by default, what's the syntax for turning it off? Is it --no-global
, --global=false
or something else? Please explain that in the docs.
docs/site/Interceptor-generator.md
Outdated
*/ | ||
|
||
value() { | ||
const interceptor: Interceptor = async (invocationCtx, next) => { |
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.
Please rework the interceptor into a named method, i.e. TestInterceptor.prototype.intercept
.
const interceptor: Interceptor = async (invocationCtx, next) => { | |
return this.intercept.bind(this); |
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.
Can you remind me why you are against using an arrow function inside value()
? Is it about the stack trace? In my test, the stack trace shows interceptor
(name of the const) as the function name, which is good to me.
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.
Yes, it's mostly about the stack trace. IMO, TestInterceptor.intercept
is most helpful.
interceptor
is not entirely bad, but I see few problems:
-
It's not clear which interceptor is involved, one has to look to the filename to find that. (This works only when there is a single interceptor exported by that source file.)
-
It's not clear why we are storing the interceptor in a local variable. Personally, I would simplify the code as follows, with unintended consequence on stack traces:
value() { return async (invocationCtx, next) => { // ... }; }
More subjectively, this is also about Single Responsibility Principle - the value
function should be concerned with obtaining the interceptor function only, the actual interception should be implemented elsewhere.
packages/boot/src/__tests__/fixtures/non-global-interceptor.artifact.ts
Outdated
Show resolved
Hide resolved
packages/cli/generators/interceptor/templates/interceptor-template.ts.ejs
Outdated
Show resolved
Hide resolved
packages/cli/test/integration/generators/interceptor.integration.js
Outdated
Show resolved
Hide resolved
bb1c657
to
1b7fe3f
Compare
1b7fe3f
to
a35ca5d
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.
Please get at least one more approval from @strongloop/loopback-maintainers before landing.
packages/context/src/interceptor.ts
Outdated
if (group) binding.tag({[ContextTags.GLOBAL_INTERCEPTOR_GROUP]: group}); | ||
}; | ||
} | ||
|
||
/** | ||
* `@globalInterceptor` decorator to mark a class a global interceptor |
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.
Missing "as"? English is not my mother tongue, I may be wrong.
* `@globalInterceptor` decorator to mark a class a global interceptor | |
* `@globalInterceptor` decorator to mark a class as a global interceptor |
@raymondfeng I am not sure if this comment has been addressed yet: #2907 (comment)
|
@bajtos Did you notice that we now have the following prompt to address #2907 (comment)?
|
a35ca5d
to
552f101
Compare
lb4 interceptor
command to generate interceptors.interceptor
booter to load interceptors fromsrc/interceptors
.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 👈