0
# Service Resolution
1
2
Dependency injection system for resolving plugin services with support for both required and optional dependencies. The Application class provides service resolution capabilities through its integrated PluginRegistry.
3
4
## Capabilities
5
6
### Required Service Resolution
7
8
Resolve services that must be available for the application to function correctly.
9
10
```typescript { .api }
11
/**
12
* Resolve a required service of a given type.
13
* @param token - The token for the service type of interest
14
* @returns A promise which resolves to an instance of the requested service, or rejects if it cannot be resolved
15
*/
16
resolveRequiredService<U>(token: Token<U>): Promise<U>;
17
```
18
19
**Usage Example:**
20
21
```typescript
22
import { Token } from "@lumino/coreutils";
23
24
// Define a service token
25
interface IDataService {
26
getData(): Promise<any[]>;
27
saveData(data: any): Promise<void>;
28
}
29
30
const IDataService = new Token<IDataService>('IDataService');
31
32
// Register a plugin that provides the service
33
app.registerPlugin({
34
id: 'data-provider',
35
provides: IDataService,
36
activate: () => ({
37
getData: async () => [{ id: 1, name: 'Sample' }],
38
saveData: async (data) => console.log('Saving:', data)
39
})
40
});
41
42
// Resolve the required service
43
try {
44
const dataService = await app.resolveRequiredService(IDataService);
45
const data = await dataService.getData();
46
console.log('Retrieved data:', data);
47
} catch (error) {
48
console.error('Failed to resolve required service:', error);
49
}
50
```
51
52
### Optional Service Resolution
53
54
Resolve services that are optional - the application can function without them.
55
56
```typescript { .api }
57
/**
58
* Resolve an optional service of a given type.
59
* @param token - The token for the service type of interest
60
* @returns A promise which resolves to an instance of the requested service, or null if it cannot be resolved
61
*/
62
resolveOptionalService<U>(token: Token<U>): Promise<U | null>;
63
```
64
65
**Usage Example:**
66
67
```typescript
68
import { Token } from "@lumino/coreutils";
69
70
// Define optional service tokens
71
interface IThemeService {
72
setTheme(theme: string): void;
73
getTheme(): string;
74
}
75
76
interface IAnalyticsService {
77
track(event: string, data?: any): void;
78
}
79
80
const IThemeService = new Token<IThemeService>('IThemeService');
81
const IAnalyticsService = new Token<IAnalyticsService>('IAnalyticsService');
82
83
// Register plugins that provide optional services
84
app.registerPlugin({
85
id: 'theme-provider',
86
provides: IThemeService,
87
activate: () => ({
88
setTheme: (theme: string) => document.body.className = `theme-${theme}`,
89
getTheme: () => 'default'
90
})
91
});
92
93
// Resolve optional services
94
const themeService = await app.resolveOptionalService(IThemeService);
95
if (themeService) {
96
themeService.setTheme('dark');
97
console.log('Theme service available');
98
} else {
99
console.log('Theme service not available, using defaults');
100
}
101
102
const analyticsService = await app.resolveOptionalService(IAnalyticsService);
103
if (analyticsService) {
104
analyticsService.track('app-started');
105
} else {
106
console.log('Analytics service not available');
107
}
108
```
109
110
### Service Tokens
111
112
Service tokens are used to identify and request specific services. They are created using the Token class from @lumino/coreutils.
113
114
```typescript { .api }
115
interface Token<T> {
116
readonly name: string;
117
}
118
119
// Token constructor (from @lumino/coreutils)
120
// new Token<T>(name: string): Token<T>
121
```
122
123
**Token Creation Examples:**
124
125
```typescript
126
import { Token } from "@lumino/coreutils";
127
128
// Service interface definitions
129
interface ILoggerService {
130
log(message: string): void;
131
error(message: string): void;
132
warn(message: string): void;
133
}
134
135
interface IConfigService {
136
get<T>(key: string): T | undefined;
137
set<T>(key: string, value: T): void;
138
}
139
140
interface INotificationService {
141
show(message: string, type?: 'info' | 'warning' | 'error'): void;
142
}
143
144
// Create service tokens
145
const ILoggerService = new Token<ILoggerService>('ILoggerService');
146
const IConfigService = new Token<IConfigService>('IConfigService');
147
const INotificationService = new Token<INotificationService>('INotificationService');
148
149
// Use tokens for service resolution
150
const logger = await app.resolveRequiredService(ILoggerService);
151
const config = await app.resolveOptionalService(IConfigService);
152
const notifications = await app.resolveOptionalService(INotificationService);
153
```
154
155
### Service Dependencies in Plugins
156
157
Plugins can declare service dependencies that will be automatically resolved when the plugin is activated.
158
159
```typescript { .api }
160
interface IPlugin<T = any, U = any> {
161
// ... other properties
162
/** Array of tokens for services this plugin requires */
163
requires?: Token<any>[];
164
/** Array of tokens for services this plugin optionally uses */
165
optional?: Token<any>[];
166
}
167
```
168
169
**Plugin with Service Dependencies:**
170
171
```typescript
172
// Plugin that requires logger and optionally uses config
173
const myPlugin: IPlugin<Application> = {
174
id: 'my-feature',
175
description: 'Feature with service dependencies',
176
requires: [ILoggerService],
177
optional: [IConfigService, INotificationService],
178
activate: (app: Application, logger: ILoggerService, config?: IConfigService, notifications?: INotificationService) => {
179
logger.log('My feature plugin activated');
180
181
// Use required service
182
logger.log('Initializing feature...');
183
184
// Use optional services if available
185
if (config) {
186
const setting = config.get<string>('my-feature.setting');
187
logger.log(`Using setting: ${setting}`);
188
}
189
190
if (notifications) {
191
notifications.show('Feature activated successfully!', 'info');
192
}
193
194
return {
195
doSomething: () => logger.log('Doing something...')
196
};
197
}
198
};
199
200
app.registerPlugin(myPlugin);
201
```
202
203
### Service Resolution Notes
204
205
**Important Behaviors:**
206
207
1. **Automatic Activation**: If a plugin providing a required service hasn't been activated yet, resolving the service will automatically activate that plugin.
208
209
2. **Singletons**: Services are singletons - the same instance is returned each time a service token is resolved.
210
211
3. **Dependency Order**: Plugins are activated in dependency order - plugins providing services are activated before plugins that require them.
212
213
4. **Circular Dependencies**: The plugin system detects and prevents circular dependency chains.
214
215
5. **Error Handling**: Required service resolution throws an error if the service cannot be provided, while optional service resolution returns null.
216
217
**Best Practices:**
218
219
- Use descriptive names for service tokens to avoid conflicts
220
- Define clear service interfaces with TypeScript types
221
- Handle optional services gracefully with null checks
222
- Prefer composition over inheritance when designing services
223
- Keep service interfaces focused and cohesive