@@ -65,6 +65,27 @@ export class MyComponent implements Component {
65
65
}
66
66
```
67
67
68
+ We recommend to component authors to use
69
+ [ Typed binding keys] ( ./Context.md#encoding-value-types-in-binding-keys )
70
+ instead of string keys and to export an object (a TypeScript namespace)
71
+ providing constants for all binding keys defined by the component.
72
+
73
+ ``` ts
74
+ import {MyValue , MyValueProvider } from ' ./providers/my-value-provider' ;
75
+
76
+ export namespace MyComponentKeys {
77
+ export const MY_VALUE = new BindingKey <MyValue >(' my-component.my-value' );
78
+ }
79
+
80
+ export class MyComponent implements Component {
81
+ constructor () {
82
+ this .providers = {
83
+ [MyComponentKeys .MY_VALUE .key ]: MyValueProvider ,
84
+ };
85
+ }
86
+ }
87
+ ```
88
+
68
89
### Accessing values from Providers
69
90
70
91
Applications can use ` @inject ` decorators to access the value of an exported
@@ -121,13 +142,12 @@ resolve them automatically.
121
142
122
143
``` ts
123
144
import {Provider } from ' @loopback/context' ;
124
- import {RestBindings } from ' @loopback/rest' ;
125
- import {ServerRequest } from ' http' ;
145
+ import {ParsedRequest , RestBindings } from ' @loopback/rest' ;
126
146
const uuid = require (' uuid/v4' );
127
147
128
148
class CorrelationIdProvider implements Provider <string > {
129
149
constructor (
130
- @inject (RestBindings .Http .REQUEST ) private request : ServerRequest ,
150
+ @inject (RestBindings .Http .REQUEST ) private request : ParsedRequest ,
131
151
) {}
132
152
133
153
value() {
@@ -147,67 +167,78 @@ The idiomatic solution has two parts:
147
167
148
168
1 . The component should define and bind a new [ Sequence action] ( Sequence.md#actions ) , for example ` authentication.actions.authenticate ` :
149
169
150
- ``` ts
151
- import {Component } from ' @loopback/core' ;
170
+ ``` ts
171
+ import {Component } from ' @loopback/core' ;
152
172
153
- class AuthenticationComponent implements Component {
154
- constructor () {
155
- this .providers = {
156
- ' authentication.actions.authenticate' : AuthenticateActionProvider ,
157
- };
158
- }
159
- }
160
- ```
173
+ export namespace AuthenticationBindings {
174
+ export const AUTH_ACTION = BindingKey .create <AuthenticateFn >(
175
+ ' authentication.actions.authenticate' ,
176
+ );
177
+ }
161
178
162
- A sequence action is typically implemented as an ` action() ` method in the provider.
179
+ class AuthenticationComponent implements Component {
180
+ constructor () {
181
+ this .providers = {
182
+ [AuthenticationBindings .AUTH_ACTION .key ]: AuthenticateActionProvider ,
183
+ };
184
+ }
185
+ }
186
+ ```
163
187
164
- ``` ts
165
- class AuthenticateActionProvider implements Provider <AuthenticateFn > {
166
- // Provider interface
167
- value() {
168
- return request => this .action (request );
169
- }
188
+ A sequence action is typically implemented as an ` action() ` method
189
+ in the provider .
170
190
171
- // The sequence action
172
- action( request ) : UserProfile | undefined {
173
- // authenticate the user
174
- }
175
- }
176
- ```
191
+ ` ` ` ts
192
+ class AuthenticateActionProvider implements Provider<AuthenticateFn> {
193
+ // Provider interface
194
+ value() {
195
+ return request => this.action(request);
196
+ }
177
197
178
- It may be tempting to put action implementation directly inside the anonymous arrow function returned by provider's ` value() ` method. We consider that as a bad practice though, because when an error occurs, the stack trace will contain only an anonymous function that makes it more difficult to link the entry with the sequence action.
198
+ // The sequence action
199
+ action(request): UserProfile | undefined {
200
+ // authenticate the user
201
+ }
202
+ }
203
+ ` ` `
204
+
205
+ It may be tempting to put action implementation directly inside
206
+ the anonymous arrow function returned by provider's `value()` method.
207
+ We consider that as a bad practice though, because when an error occurs,
208
+ the stack trace will contain only an anonymous function that makes it more
209
+ difficult to link the entry with the sequence action.
179
210
180
211
2. The application should use a custom ` Sequence ` class which calls this new sequence action in an appropriate place .
181
212
182
- ``` ts
183
- class AppSequence implements SequenceHandler {
184
- constructor (
185
- @inject (RestBindings .Http .CONTEXT ) protected ctx : Context ,
186
- @inject (RestBindings .SequenceActions .FIND_ROUTE ) protected findRoute : FindRoute ,
187
- @inject (RestBindings .SequenceActions .PARSE_PARAMS ) protected parseParams : ParseParams ,
188
- @inject (RestBindings .SequenceActions .INVOKE_METHOD ) protected invoke : InvokeMethod ,
189
- @inject (RestBindings .SequenceActions .SEND ) public send : Send ,
190
- @inject (RestBindings .SequenceActions .REJECT ) public reject : Reject ,
191
- // Inject the new action here:
192
- @inject (' authentication.actions.authenticate' ) protected authenticate : AuthenticateFn
193
- ) {}
194
-
195
- async handle(req : ParsedRequest , res : ServerResponse ) {
196
- try {
197
- const route = this .findRoute (req );
198
-
199
- // Invoke the new action:
200
- const user = await this .authenticate (req );
201
-
202
- const args = await parseOperationArgs (req , route );
203
- const result = await this .invoke (route , args );
204
- this .send (res , result );
205
- } catch (err ) {
206
- this .reject (res , req , err );
207
- }
208
- }
209
- }
210
- ```
213
+ ```ts
214
+ class AppSequence implements SequenceHandler {
215
+ constructor (
216
+ @inject (RestBindings .Http .CONTEXT ) protected ctx : Context ,
217
+ @inject (RestBindings .SequenceActions .FIND_ROUTE ) protected findRoute : FindRoute ,
218
+ @inject (RestBindings .SequenceActions .PARSE_PARAMS ) protected parseParams : ParseParams ,
219
+ @inject (RestBindings .SequenceActions .INVOKE_METHOD ) protected invoke : InvokeMethod ,
220
+ @inject (RestBindings .SequenceActions .SEND ) public send : Send ,
221
+ @inject (RestBindings .SequenceActions .REJECT ) public reject : Reject ,
222
+ // Inject the new action here:
223
+ @inject (' authentication.actions.authenticate' ) protected authenticate : AuthenticateFn
224
+ ) {}
225
+
226
+ async handle(req : ParsedRequest , res : ServerResponse ) {
227
+ try {
228
+ const route = this .findRoute (req );
229
+
230
+ // Invoke the new action:
231
+ const user = await this .authenticate (req );
232
+
233
+ const args = await parseOperationArgs (req , route );
234
+ const result = await this .invoke (route , args );
235
+ this .send (res , result );
236
+ } catch (err ) {
237
+ this .reject (res , req , err );
238
+ }
239
+ }
240
+ }
241
+ ```
211
242
212
243
### Accessing Elements contributed by other Sequence Actions
213
244
@@ -223,7 +254,7 @@ of the actual value. This allows you to defer resolution of your dependency only
223
254
until the sequence action contributing this value has already finished.
224
255
225
256
` ` ` ts
226
- export class AuthenticationProvider implements Provider <AuthenticateFn > {
257
+ export class AuthenticateActionProvider implements Provider<AuthenticateFn> {
227
258
constructor(
228
259
@inject.getter(BindingKeys.Authentication.STRATEGY)
229
260
readonly getStrategy
@@ -233,7 +264,7 @@ export class AuthenticationProvider implements Provider<AuthenticateFn> {
233
264
return request => this.action(request);
234
265
}
235
266
236
- async action(request ): UserProfile | undefined {
267
+ async action(request): Promise< UserProfile | undefined> {
237
268
const strategy = await this.getStrategy();
238
269
// ...
239
270
}
@@ -246,7 +277,7 @@ Use `@inject.setter` decorator to obtain a setter function that can be used to
246
277
contribute new Elements to the request context.
247
278
248
279
` ` ` ts
249
- export class AuthenticationProvider implements Provider <AuthenticateFn > {
280
+ export class AuthenticateActionProvider implements Provider<AuthenticateFn> {
250
281
constructor(
251
282
@inject.getter(BindingKeys.Authentication.STRATEGY) readonly getStrategy,
252
283
@inject.setter(BindingKeys.Authentication.CURRENT_USER)
@@ -259,7 +290,8 @@ export class AuthenticationProvider implements Provider<AuthenticateFn> {
259
290
260
291
async action(request): UserProfile | undefined {
261
292
const strategy = await this.getStrategy();
262
- const user = this .setCurrentUser (user ); // ... authenticate
293
+ // (authenticate the request using the obtained strategy)
294
+ const user = this.setCurrentUser(user);
263
295
return user;
264
296
}
265
297
}
0 commit comments