@acontplus/ng-infrastructure 1.0.8 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +320 -45
- package/fesm2022/acontplus-ng-infrastructure.mjs +44 -71
- package/fesm2022/acontplus-ng-infrastructure.mjs.map +1 -1
- package/index.d.ts +11 -54
- package/package.json +23 -9
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @acontplus/ng-infrastructure
|
|
2
2
|
|
|
3
|
-
Angular infrastructure library
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Angular infrastructure library providing HTTP interceptors, repositories,
|
|
4
|
+
adapters, and core services following clean architecture patterns for robust
|
|
5
|
+
enterprise applications.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -12,86 +12,361 @@ npm install @acontplus/ng-infrastructure
|
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
-
- **HTTP Interceptors**: API handling, HTTP context management,
|
|
16
|
-
|
|
17
|
-
- **
|
|
18
|
-
|
|
19
|
-
- **Adapters**:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
|
|
15
|
+
- **HTTP Interceptors**: API request/response handling, HTTP context management,
|
|
16
|
+
and loading indicators
|
|
17
|
+
- **Repository Pattern**: Base HTTP repository, generic repository, and
|
|
18
|
+
repository factory
|
|
19
|
+
- **HTTP Adapters**: Angular HTTP client adapter for external service
|
|
20
|
+
integration
|
|
21
|
+
- **Core Services**: Configuration, correlation tracking, logging, and tenant
|
|
22
|
+
management
|
|
23
|
+
- **Use Cases**: Base use case patterns with command and query separation (CQRS)
|
|
24
|
+
- **Clean Architecture**: Separation of concerns with infrastructure layer
|
|
25
|
+
abstractions
|
|
26
|
+
- **TypeScript Support**: Full type safety with comprehensive interfaces
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Configure Interceptors
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import {
|
|
34
|
+
apiInterceptor,
|
|
35
|
+
httpContextInterceptor,
|
|
36
|
+
spinnerInterceptor,
|
|
37
|
+
} from '@acontplus/ng-infrastructure';
|
|
38
|
+
|
|
39
|
+
// In app.config.ts
|
|
40
|
+
export const appConfig: ApplicationConfig = {
|
|
41
|
+
providers: [
|
|
42
|
+
provideHttpClient(
|
|
43
|
+
withInterceptors([
|
|
44
|
+
apiInterceptor,
|
|
45
|
+
spinnerInterceptor,
|
|
46
|
+
httpContextInterceptor,
|
|
47
|
+
]),
|
|
48
|
+
),
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## HTTP Interceptors
|
|
28
54
|
|
|
29
55
|
### API Interceptor
|
|
30
56
|
|
|
31
|
-
Handles API
|
|
57
|
+
Handles API request/response transformation and error handling.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { apiInterceptor } from '@acontplus/ng-infrastructure';
|
|
61
|
+
|
|
62
|
+
// Automatically handles:
|
|
63
|
+
// - Request/response transformation
|
|
64
|
+
// - Error standardization
|
|
65
|
+
// - API base URL configuration
|
|
66
|
+
// - Response format normalization
|
|
67
|
+
```
|
|
32
68
|
|
|
33
69
|
### HTTP Context Interceptor
|
|
34
70
|
|
|
35
|
-
Manages HTTP context for
|
|
71
|
+
Manages HTTP context and correlation IDs for request tracing.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { httpContextInterceptor } from '@acontplus/ng-infrastructure';
|
|
75
|
+
|
|
76
|
+
// Automatically adds:
|
|
77
|
+
// - Correlation IDs to requests
|
|
78
|
+
// - Request context information
|
|
79
|
+
// - Tenant information
|
|
80
|
+
// - Request metadata
|
|
81
|
+
```
|
|
36
82
|
|
|
37
83
|
### Spinner Interceptor
|
|
38
84
|
|
|
39
|
-
Manages loading
|
|
85
|
+
Manages loading indicators during HTTP operations.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { spinnerInterceptor } from '@acontplus/ng-infrastructure';
|
|
89
|
+
|
|
90
|
+
// Automatically handles:
|
|
91
|
+
// - Loading state management
|
|
92
|
+
// - Spinner show/hide logic
|
|
93
|
+
// - Multiple concurrent request handling
|
|
94
|
+
// - Error state cleanup
|
|
95
|
+
```
|
|
40
96
|
|
|
41
|
-
##
|
|
97
|
+
## Repository Pattern
|
|
42
98
|
|
|
43
99
|
### Base HTTP Repository
|
|
44
100
|
|
|
45
|
-
|
|
101
|
+
Abstract base class for HTTP-based data access.
|
|
46
102
|
|
|
47
|
-
|
|
103
|
+
```typescript
|
|
104
|
+
import { BaseHttpRepository } from '@acontplus/ng-infrastructure';
|
|
105
|
+
import { Injectable } from '@angular/core';
|
|
106
|
+
import { HttpClient } from '@angular/common/http';
|
|
107
|
+
|
|
108
|
+
interface User {
|
|
109
|
+
id: number;
|
|
110
|
+
name: string;
|
|
111
|
+
email: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@Injectable({ providedIn: 'root' })
|
|
115
|
+
export class UserRepository extends BaseHttpRepository<User> {
|
|
116
|
+
constructor(http: HttpClient) {
|
|
117
|
+
super(http, '/api/users');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Inherits common CRUD operations:
|
|
121
|
+
// - getById(id: number)
|
|
122
|
+
// - getAll()
|
|
123
|
+
// - create(entity: User)
|
|
124
|
+
// - update(id: number, entity: Partial<User>)
|
|
125
|
+
// - delete(id: number)
|
|
126
|
+
}
|
|
127
|
+
```
|
|
48
128
|
|
|
49
|
-
Generic
|
|
129
|
+
### Generic Repository
|
|
50
130
|
|
|
51
|
-
|
|
131
|
+
Generic repository implementation with type safety.
|
|
52
132
|
|
|
53
|
-
|
|
133
|
+
```typescript
|
|
134
|
+
import { GenericRepository } from '@acontplus/ng-infrastructure';
|
|
135
|
+
|
|
136
|
+
@Injectable({ providedIn: 'root' })
|
|
137
|
+
export class CustomerRepository extends GenericRepository<Customer, number> {
|
|
138
|
+
constructor(http: HttpClient) {
|
|
139
|
+
super(http, '/api/customers');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Custom business methods
|
|
143
|
+
async findByEmail(email: string): Promise<Customer[]> {
|
|
144
|
+
return (
|
|
145
|
+
this.http
|
|
146
|
+
.get<Customer[]>(`${this.baseUrl}/search?email=${email}`)
|
|
147
|
+
.toPromise() || []
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
54
152
|
|
|
55
153
|
### Repository Factory
|
|
56
154
|
|
|
57
|
-
Factory for creating repository instances.
|
|
155
|
+
Factory pattern for creating repository instances.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { RepositoryFactory } from '@acontplus/ng-infrastructure';
|
|
159
|
+
|
|
160
|
+
@Injectable({ providedIn: 'root' })
|
|
161
|
+
export class DataService {
|
|
162
|
+
constructor(private repositoryFactory: RepositoryFactory) {}
|
|
163
|
+
|
|
164
|
+
getUserRepository() {
|
|
165
|
+
return this.repositoryFactory.create<User>('users');
|
|
166
|
+
}
|
|
58
167
|
|
|
59
|
-
|
|
168
|
+
getCustomerRepository() {
|
|
169
|
+
return this.repositoryFactory.create<Customer>('customers');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## HTTP Adapters
|
|
175
|
+
|
|
176
|
+
### Angular HTTP Adapter
|
|
177
|
+
|
|
178
|
+
Adapter for Angular HTTP client integration.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { AngularHttpAdapter } from '@acontplus/ng-infrastructure';
|
|
182
|
+
|
|
183
|
+
@Injectable({ providedIn: 'root' })
|
|
184
|
+
export class ExternalApiService {
|
|
185
|
+
constructor(private httpAdapter: AngularHttpAdapter) {}
|
|
186
|
+
|
|
187
|
+
async fetchExternalData(url: string): Promise<any> {
|
|
188
|
+
return this.httpAdapter.get(url);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async postData(url: string, data: any): Promise<any> {
|
|
192
|
+
return this.httpAdapter.post(url, data);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Core Services
|
|
60
198
|
|
|
61
199
|
### Core Config Service
|
|
62
200
|
|
|
63
|
-
Manages
|
|
201
|
+
Manages application configuration and settings.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { CoreConfigService } from '@acontplus/ng-infrastructure';
|
|
205
|
+
|
|
206
|
+
@Injectable({ providedIn: 'root' })
|
|
207
|
+
export class AppService {
|
|
208
|
+
constructor(private configService: CoreConfigService) {}
|
|
209
|
+
|
|
210
|
+
getApiBaseUrl(): string {
|
|
211
|
+
return this.configService.getApiBaseUrl();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
getTimeout(): number {
|
|
215
|
+
return this.configService.getTimeout();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
64
219
|
|
|
65
220
|
### Correlation Service
|
|
66
221
|
|
|
67
|
-
Handles correlation IDs for request tracing.
|
|
222
|
+
Handles correlation IDs for distributed request tracing.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { CorrelationInfo } from '@acontplus/ng-infrastructure';
|
|
226
|
+
|
|
227
|
+
@Injectable({ providedIn: 'root' })
|
|
228
|
+
export class TrackingService {
|
|
229
|
+
constructor(private correlationInfo: CorrelationInfo) {}
|
|
230
|
+
|
|
231
|
+
getCurrentCorrelationId(): string {
|
|
232
|
+
return this.correlationInfo.getCorrelationId();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
generateNewCorrelationId(): string {
|
|
236
|
+
return this.correlationInfo.generateCorrelationId();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
68
240
|
|
|
69
241
|
### Logging Service
|
|
70
242
|
|
|
71
|
-
|
|
243
|
+
Structured logging with correlation tracking.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { LoggingService } from '@acontplus/ng-infrastructure';
|
|
247
|
+
|
|
248
|
+
@Injectable({ providedIn: 'root' })
|
|
249
|
+
export class BusinessService {
|
|
250
|
+
constructor(private logger: LoggingService) {}
|
|
251
|
+
|
|
252
|
+
processOrder(order: Order): void {
|
|
253
|
+
this.logger.info('Processing order', { orderId: order.id });
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
// Business logic
|
|
257
|
+
this.logger.info('Order processed successfully', { orderId: order.id });
|
|
258
|
+
} catch (error) {
|
|
259
|
+
this.logger.error('Order processing failed', error, {
|
|
260
|
+
orderId: order.id,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
72
266
|
|
|
73
267
|
### Tenant Service
|
|
74
268
|
|
|
75
|
-
|
|
269
|
+
Multi-tenant application support.
|
|
76
270
|
|
|
77
|
-
|
|
271
|
+
```typescript
|
|
272
|
+
import { TenantInfo } from '@acontplus/ng-infrastructure';
|
|
78
273
|
|
|
79
|
-
|
|
274
|
+
@Injectable({ providedIn: 'root' })
|
|
275
|
+
export class MultiTenantService {
|
|
276
|
+
constructor(private tenantInfo: TenantInfo) {}
|
|
80
277
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
spinnerInterceptor,
|
|
85
|
-
} from '@acontplus/ng-infrastructure';
|
|
278
|
+
getCurrentTenant(): string {
|
|
279
|
+
return this.tenantInfo.getTenantId();
|
|
280
|
+
}
|
|
86
281
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
282
|
+
setTenant(tenantId: string): void {
|
|
283
|
+
this.tenantInfo.setTenantId(tenantId);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Use Cases (CQRS Pattern)
|
|
289
|
+
|
|
290
|
+
### Base Use Case
|
|
291
|
+
|
|
292
|
+
Abstract base class for business logic encapsulation.
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { BaseUseCase } from '@acontplus/ng-infrastructure';
|
|
296
|
+
|
|
297
|
+
export class CreateUserUseCase extends BaseUseCase<CreateUserCommand, User> {
|
|
298
|
+
constructor(
|
|
299
|
+
private userRepository: UserRepository,
|
|
300
|
+
private logger: LoggingService,
|
|
301
|
+
) {
|
|
302
|
+
super();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async execute(command: CreateUserCommand): Promise<User> {
|
|
306
|
+
this.logger.info('Creating user', { email: command.email });
|
|
307
|
+
|
|
308
|
+
// Validation
|
|
309
|
+
this.validateCommand(command);
|
|
310
|
+
|
|
311
|
+
// Business logic
|
|
312
|
+
const user = await this.userRepository.create({
|
|
313
|
+
name: command.name,
|
|
314
|
+
email: command.email,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
this.logger.info('User created successfully', { userId: user.id });
|
|
318
|
+
return user;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
private validateCommand(command: CreateUserCommand): void {
|
|
322
|
+
if (!command.email || !command.name) {
|
|
323
|
+
throw new Error('Email and name are required');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
93
327
|
```
|
|
94
328
|
|
|
95
|
-
|
|
329
|
+
### Commands and Queries
|
|
330
|
+
|
|
331
|
+
Separation of read and write operations.
|
|
96
332
|
|
|
97
|
-
|
|
333
|
+
```typescript
|
|
334
|
+
import { Commands, Queries } from '@acontplus/ng-infrastructure';
|
|
335
|
+
|
|
336
|
+
// Command for write operations
|
|
337
|
+
export class UpdateUserCommand extends Commands.BaseCommand {
|
|
338
|
+
constructor(
|
|
339
|
+
public readonly userId: number,
|
|
340
|
+
public readonly name: string,
|
|
341
|
+
public readonly email: string,
|
|
342
|
+
) {
|
|
343
|
+
super();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Query for read operations
|
|
348
|
+
export class GetUserQuery extends Queries.BaseQuery<User> {
|
|
349
|
+
constructor(public readonly userId: number) {
|
|
350
|
+
super();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Usage
|
|
355
|
+
@Injectable({ providedIn: 'root' })
|
|
356
|
+
export class UserService {
|
|
357
|
+
constructor(
|
|
358
|
+
private updateUserUseCase: UpdateUserUseCase,
|
|
359
|
+
private getUserUseCase: GetUserUseCase,
|
|
360
|
+
) {}
|
|
361
|
+
|
|
362
|
+
async updateUser(userId: number, name: string, email: string): Promise<User> {
|
|
363
|
+
const command = new UpdateUserCommand(userId, name, email);
|
|
364
|
+
return this.updateUserUseCase.execute(command);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async getUser(userId: number): Promise<User> {
|
|
368
|
+
const query = new GetUserQuery(userId);
|
|
369
|
+
return this.getUserUseCase.execute(query);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|