@biggora/claude-plugins 1.2.2 → 1.3.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 +5 -1
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +11 -0
- package/src/commands/skills/add.js +115 -31
- package/src/commands/skills/list.js +25 -52
- package/src/commands/skills/remove.js +45 -27
- package/src/commands/skills/resolve.js +104 -0
- package/src/commands/skills/update.js +58 -74
- package/src/config.js +5 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-interceptors
|
|
3
|
+
description: NestJS interceptors for aspect-oriented programming
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Interceptors
|
|
7
|
+
|
|
8
|
+
Interceptors implement aspect-oriented programming (AOP). They can bind extra logic before/after method execution, transform results, handle exceptions, and extend function behavior.
|
|
9
|
+
|
|
10
|
+
## Basic Interceptor
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
14
|
+
import { Observable } from 'rxjs';
|
|
15
|
+
import { tap } from 'rxjs/operators';
|
|
16
|
+
|
|
17
|
+
@Injectable()
|
|
18
|
+
export class LoggingInterceptor implements NestInterceptor {
|
|
19
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
20
|
+
console.log('Before...');
|
|
21
|
+
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
return next
|
|
24
|
+
.handle()
|
|
25
|
+
.pipe(
|
|
26
|
+
tap(() => console.log(`After... ${Date.now() - now}ms`)),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Response Transformation
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
36
|
+
import { Observable } from 'rxjs';
|
|
37
|
+
import { map } from 'rxjs/operators';
|
|
38
|
+
|
|
39
|
+
export interface Response<T> {
|
|
40
|
+
data: T;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Injectable()
|
|
44
|
+
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
|
|
45
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
|
|
46
|
+
return next.handle().pipe(map(data => ({ data })));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Exception Mapping
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import {
|
|
55
|
+
Injectable,
|
|
56
|
+
NestInterceptor,
|
|
57
|
+
ExecutionContext,
|
|
58
|
+
BadGatewayException,
|
|
59
|
+
CallHandler,
|
|
60
|
+
} from '@nestjs/common';
|
|
61
|
+
import { Observable, throwError } from 'rxjs';
|
|
62
|
+
import { catchError } from 'rxjs/operators';
|
|
63
|
+
|
|
64
|
+
@Injectable()
|
|
65
|
+
export class ErrorsInterceptor implements NestInterceptor {
|
|
66
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
67
|
+
return next
|
|
68
|
+
.handle()
|
|
69
|
+
.pipe(
|
|
70
|
+
catchError(err => throwError(() => new BadGatewayException())),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Caching Interceptor
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
80
|
+
import { Observable, of } from 'rxjs';
|
|
81
|
+
|
|
82
|
+
@Injectable()
|
|
83
|
+
export class CacheInterceptor implements NestInterceptor {
|
|
84
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
85
|
+
const isCached = true;
|
|
86
|
+
if (isCached) {
|
|
87
|
+
return of([]);
|
|
88
|
+
}
|
|
89
|
+
return next.handle();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Timeout Interceptor
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, RequestTimeoutException } from '@nestjs/common';
|
|
98
|
+
import { Observable, throwError, TimeoutError } from 'rxjs';
|
|
99
|
+
import { catchError, timeout } from 'rxjs/operators';
|
|
100
|
+
|
|
101
|
+
@Injectable()
|
|
102
|
+
export class TimeoutInterceptor implements NestInterceptor {
|
|
103
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
104
|
+
return next.handle().pipe(
|
|
105
|
+
timeout(5000),
|
|
106
|
+
catchError(err => {
|
|
107
|
+
if (err instanceof TimeoutError) {
|
|
108
|
+
return throwError(() => new RequestTimeoutException());
|
|
109
|
+
}
|
|
110
|
+
return throwError(() => err);
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Binding Interceptors
|
|
118
|
+
|
|
119
|
+
### Controller-scoped
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
@Controller('cats')
|
|
123
|
+
@UseInterceptors(LoggingInterceptor)
|
|
124
|
+
export class CatsController {}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Method-scoped
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
@Get()
|
|
131
|
+
@UseInterceptors(LoggingInterceptor)
|
|
132
|
+
async findAll() {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Global Interceptors
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const app = await NestFactory.create(AppModule);
|
|
141
|
+
app.useGlobalInterceptors(new LoggingInterceptor());
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Or via module:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { Module } from '@nestjs/common';
|
|
148
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
149
|
+
|
|
150
|
+
@Module({
|
|
151
|
+
providers: [
|
|
152
|
+
{
|
|
153
|
+
provide: APP_INTERCEPTOR,
|
|
154
|
+
useClass: LoggingInterceptor,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
})
|
|
158
|
+
export class AppModule {}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Null Transformation
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
@Injectable()
|
|
165
|
+
export class ExcludeNullInterceptor implements NestInterceptor {
|
|
166
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
167
|
+
return next
|
|
168
|
+
.handle()
|
|
169
|
+
.pipe(map(value => value === null ? '' : value));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Key Points
|
|
175
|
+
|
|
176
|
+
- Interceptors wrap request/response stream
|
|
177
|
+
- Use RxJS operators to manipulate streams
|
|
178
|
+
- Must call `next.handle()` to continue execution
|
|
179
|
+
- Can transform responses using `map()`
|
|
180
|
+
- Can handle errors using `catchError()`
|
|
181
|
+
- Can override stream completely (caching)
|
|
182
|
+
- Interceptors support dependency injection
|
|
183
|
+
|
|
184
|
+
<!--
|
|
185
|
+
Source references:
|
|
186
|
+
- https://docs.nestjs.com/interceptors
|
|
187
|
+
-->
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lazy-loading
|
|
3
|
+
description: Lazy loading modules for serverless and performance optimization
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lazy Loading Modules
|
|
7
|
+
|
|
8
|
+
Lazy loading helps decrease bootstrap time by loading modules only when needed, particularly useful for serverless environments where cold start latency matters.
|
|
9
|
+
|
|
10
|
+
## Basic Usage
|
|
11
|
+
|
|
12
|
+
Inject `LazyModuleLoader` to load modules on-demand:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { Injectable } from '@nestjs/common';
|
|
16
|
+
import { LazyModuleLoader } from '@nestjs/core';
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class CatsService {
|
|
20
|
+
constructor(private lazyModuleLoader: LazyModuleLoader) {}
|
|
21
|
+
|
|
22
|
+
async loadFeature() {
|
|
23
|
+
const { LazyModule } = await import('./lazy.module');
|
|
24
|
+
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule);
|
|
25
|
+
|
|
26
|
+
const { LazyService } = await import('./lazy.service');
|
|
27
|
+
const lazyService = moduleRef.get(LazyService);
|
|
28
|
+
return lazyService.doSomething();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Module Definition
|
|
34
|
+
|
|
35
|
+
Lazy loaded modules are standard Nest modules:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
@Module({
|
|
39
|
+
providers: [LazyService],
|
|
40
|
+
exports: [LazyService],
|
|
41
|
+
})
|
|
42
|
+
export class LazyModule {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Caching Behavior
|
|
46
|
+
|
|
47
|
+
Lazy loaded modules are cached after the first load:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
Load "LazyModule" attempt: 1 - time: 2.379ms
|
|
51
|
+
Load "LazyModule" attempt: 2 - time: 0.294ms // Cached
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Limitations
|
|
55
|
+
|
|
56
|
+
**Cannot lazy load:**
|
|
57
|
+
- Controllers (routes must be registered at startup)
|
|
58
|
+
- Resolvers (GraphQL schema generated at startup)
|
|
59
|
+
- Gateways (WebSocket routes registered at startup)
|
|
60
|
+
|
|
61
|
+
**Other restrictions:**
|
|
62
|
+
- Cannot register as global modules
|
|
63
|
+
- Global enhancers (guards/interceptors) won't work
|
|
64
|
+
- Lifecycle hooks are not invoked in lazy loaded modules
|
|
65
|
+
|
|
66
|
+
## Webpack Configuration
|
|
67
|
+
|
|
68
|
+
For Webpack, update `tsconfig.json`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"compilerOptions": {
|
|
73
|
+
"module": "esnext",
|
|
74
|
+
"moduleResolution": "node"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
Best suited for:
|
|
82
|
+
- Serverless functions (Lambda, Cloud Functions)
|
|
83
|
+
- Worker/cron jobs with conditional logic
|
|
84
|
+
- Feature modules loaded based on runtime conditions
|
|
85
|
+
|
|
86
|
+
<!--
|
|
87
|
+
Source references:
|
|
88
|
+
- https://docs.nestjs.com/fundamentals/lazy-loading-modules
|
|
89
|
+
-->
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lifecycle-events
|
|
3
|
+
description: Application and provider lifecycle hooks in NestJS
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lifecycle Events
|
|
7
|
+
|
|
8
|
+
NestJS provides lifecycle hooks that give visibility into key application events and allow running code when they occur.
|
|
9
|
+
|
|
10
|
+
## Lifecycle Sequence
|
|
11
|
+
|
|
12
|
+
The lifecycle consists of three phases: **initializing**, **running**, and **terminating**.
|
|
13
|
+
|
|
14
|
+
## Lifecycle Hooks
|
|
15
|
+
|
|
16
|
+
| Hook | When Triggered |
|
|
17
|
+
|------|----------------|
|
|
18
|
+
| `onModuleInit()` | Called once the host module's dependencies have been resolved |
|
|
19
|
+
| `onApplicationBootstrap()` | Called once all modules have been initialized, but before listening |
|
|
20
|
+
| `onModuleDestroy()` | Called after a termination signal (e.g., SIGTERM) has been received |
|
|
21
|
+
| `beforeApplicationShutdown()` | Called after all `onModuleDestroy()` handlers have completed |
|
|
22
|
+
| `onApplicationShutdown()` | Called after connections close (`app.close()` resolves) |
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
Implement the appropriate interface to register a lifecycle hook:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { Injectable, OnModuleInit, OnApplicationBootstrap } from '@nestjs/common';
|
|
30
|
+
|
|
31
|
+
@Injectable()
|
|
32
|
+
export class UsersService implements OnModuleInit, OnApplicationBootstrap {
|
|
33
|
+
onModuleInit() {
|
|
34
|
+
console.log('Module initialized');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onApplicationBootstrap() {
|
|
38
|
+
console.log('Application bootstrapped');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Asynchronous Initialization
|
|
44
|
+
|
|
45
|
+
Hooks can be async - Nest will wait for the promise to resolve:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
async onModuleInit(): Promise<void> {
|
|
49
|
+
await this.fetchConfiguration();
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Enabling Shutdown Hooks
|
|
54
|
+
|
|
55
|
+
Shutdown hooks are disabled by default. Enable them in `main.ts`:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
async function bootstrap() {
|
|
59
|
+
const app = await NestFactory.create(AppModule);
|
|
60
|
+
app.enableShutdownHooks();
|
|
61
|
+
await app.listen(3000);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Handle shutdown signals:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
@Injectable()
|
|
69
|
+
class DatabaseService implements OnApplicationShutdown {
|
|
70
|
+
onApplicationShutdown(signal: string) {
|
|
71
|
+
console.log(`Received ${signal}, closing connections...`);
|
|
72
|
+
// Cleanup logic
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Key Points
|
|
78
|
+
|
|
79
|
+
- Lifecycle hooks are not triggered for **request-scoped** providers
|
|
80
|
+
- Execution order depends on module import order
|
|
81
|
+
- Windows has limited shutdown hook support (SIGINT works, SIGTERM doesn't)
|
|
82
|
+
- `enableShutdownHooks` consumes memory by starting listeners
|
|
83
|
+
|
|
84
|
+
<!--
|
|
85
|
+
Source references:
|
|
86
|
+
- https://docs.nestjs.com/fundamentals/lifecycle-events
|
|
87
|
+
-->
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: module-reference
|
|
3
|
+
description: Accessing providers dynamically with ModuleRef
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Module Reference
|
|
7
|
+
|
|
8
|
+
`ModuleRef` provides methods to navigate the DI container and obtain references to providers dynamically.
|
|
9
|
+
|
|
10
|
+
## Basic Usage
|
|
11
|
+
|
|
12
|
+
Inject `ModuleRef` to access providers:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
16
|
+
import { ModuleRef } from '@nestjs/core';
|
|
17
|
+
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class CatsService implements OnModuleInit {
|
|
20
|
+
private service: Service;
|
|
21
|
+
|
|
22
|
+
constructor(private moduleRef: ModuleRef) {}
|
|
23
|
+
|
|
24
|
+
onModuleInit() {
|
|
25
|
+
this.service = this.moduleRef.get(Service);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Retrieving Instances
|
|
31
|
+
|
|
32
|
+
### Static Instances (`get()`)
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// From current module
|
|
36
|
+
const service = this.moduleRef.get(Service);
|
|
37
|
+
|
|
38
|
+
// From global context (different module)
|
|
39
|
+
const service = this.moduleRef.get(Service, { strict: false });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Scoped Providers (`resolve()`)
|
|
43
|
+
|
|
44
|
+
For transient or request-scoped providers:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const transientService = await this.moduleRef.resolve(TransientService);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each `resolve()` call returns a unique instance. To get the same instance, pass a context identifier:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { ContextIdFactory } from '@nestjs/core';
|
|
54
|
+
|
|
55
|
+
const contextId = ContextIdFactory.create();
|
|
56
|
+
const service1 = await this.moduleRef.resolve(TransientService, contextId);
|
|
57
|
+
const service2 = await this.moduleRef.resolve(TransientService, contextId);
|
|
58
|
+
// service1 === service2
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Request Context
|
|
62
|
+
|
|
63
|
+
Get the context ID from an existing request:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
@Injectable()
|
|
67
|
+
export class CatsService {
|
|
68
|
+
constructor(
|
|
69
|
+
@Inject(REQUEST) private request: Record<string, unknown>,
|
|
70
|
+
private moduleRef: ModuleRef,
|
|
71
|
+
) {}
|
|
72
|
+
|
|
73
|
+
async getRepository() {
|
|
74
|
+
const contextId = ContextIdFactory.getByRequest(this.request);
|
|
75
|
+
return this.moduleRef.resolve(CatsRepository, contextId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Dynamic Instantiation
|
|
81
|
+
|
|
82
|
+
Create instances of classes not registered as providers:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const factory = await this.moduleRef.create(CatsFactory);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Register REQUEST Provider
|
|
89
|
+
|
|
90
|
+
For manually created DI sub-trees:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const contextId = ContextIdFactory.create();
|
|
94
|
+
this.moduleRef.registerRequestByContextId(myRequestObject, contextId);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Key Points
|
|
98
|
+
|
|
99
|
+
- `get()` only retrieves static (singleton) instances
|
|
100
|
+
- `resolve()` is async and for scoped providers
|
|
101
|
+
- Use `{ strict: false }` to access providers from other modules
|
|
102
|
+
- `ModuleRef` is imported from `@nestjs/core`
|
|
103
|
+
|
|
104
|
+
<!--
|
|
105
|
+
Source references:
|
|
106
|
+
- https://docs.nestjs.com/fundamentals/module-ref
|
|
107
|
+
-->
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fundamentals-pipes
|
|
3
|
+
description: NestJS pipes for data transformation and validation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pipes
|
|
7
|
+
|
|
8
|
+
Pipes transform input data to the desired form or validate input data. They operate on arguments before route handlers are invoked.
|
|
9
|
+
|
|
10
|
+
## Built-in Pipes
|
|
11
|
+
|
|
12
|
+
- `ValidationPipe` - Validates DTOs
|
|
13
|
+
- `ParseIntPipe` - Parses strings to integers
|
|
14
|
+
- `ParseFloatPipe` - Parses strings to floats
|
|
15
|
+
- `ParseBoolPipe` - Parses strings to booleans
|
|
16
|
+
- `ParseArrayPipe` - Parses strings to arrays
|
|
17
|
+
- `ParseUUIDPipe` - Validates UUIDs
|
|
18
|
+
- `ParseEnumPipe` - Validates enum values
|
|
19
|
+
- `DefaultValuePipe` - Provides default values
|
|
20
|
+
- `ParseFilePipe` - Validates file uploads
|
|
21
|
+
- `ParseDatePipe` - Parses date strings
|
|
22
|
+
|
|
23
|
+
## Binding Pipes
|
|
24
|
+
|
|
25
|
+
### Parameter-level Binding
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
@Get(':id')
|
|
29
|
+
async findOne(@Param('id', ParseIntPipe) id: number) {
|
|
30
|
+
return this.catsService.findOne(id);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### With Options
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
@Get(':id')
|
|
38
|
+
async findOne(
|
|
39
|
+
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
|
|
40
|
+
id: number,
|
|
41
|
+
) {
|
|
42
|
+
return this.catsService.findOne(id);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Query Parameters
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
@Get()
|
|
50
|
+
async findOne(@Query('id', ParseIntPipe) id: number) {
|
|
51
|
+
return this.catsService.findOne(id);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Custom Pipes
|
|
56
|
+
|
|
57
|
+
### Basic Pipe
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
|
|
61
|
+
|
|
62
|
+
@Injectable()
|
|
63
|
+
export class ValidationPipe implements PipeTransform {
|
|
64
|
+
transform(value: any, metadata: ArgumentMetadata) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Validation Pipe with Zod
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { PipeTransform, ArgumentMetadata, BadRequestException } from '@nestjs/common';
|
|
74
|
+
import { ZodSchema } from 'zod';
|
|
75
|
+
|
|
76
|
+
export class ZodValidationPipe implements PipeTransform {
|
|
77
|
+
constructor(private schema: ZodSchema) {}
|
|
78
|
+
|
|
79
|
+
transform(value: unknown, metadata: ArgumentMetadata) {
|
|
80
|
+
try {
|
|
81
|
+
const parsedValue = this.schema.parse(value);
|
|
82
|
+
return parsedValue;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
throw new BadRequestException('Validation failed');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Usage:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
@Post()
|
|
94
|
+
@UsePipes(new ZodValidationPipe(createCatSchema))
|
|
95
|
+
async create(@Body() createCatDto: CreateCatDto) {
|
|
96
|
+
this.catsService.create(createCatDto);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Validation Pipe with class-validator
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
|
|
104
|
+
import { validate } from 'class-validator';
|
|
105
|
+
import { plainToInstance } from 'class-transformer';
|
|
106
|
+
|
|
107
|
+
@Injectable()
|
|
108
|
+
export class ValidationPipe implements PipeTransform<any> {
|
|
109
|
+
async transform(value: any, { metatype }: ArgumentMetadata) {
|
|
110
|
+
if (!metatype || !this.toValidate(metatype)) {
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
const object = plainToInstance(metatype, value);
|
|
114
|
+
const errors = await validate(object);
|
|
115
|
+
if (errors.length > 0) {
|
|
116
|
+
throw new BadRequestException('Validation failed');
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private toValidate(metatype: Function): boolean {
|
|
122
|
+
const types: Function[] = [String, Boolean, Number, Array, Object];
|
|
123
|
+
return !types.includes(metatype);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Transformation Pipe
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
|
|
132
|
+
|
|
133
|
+
@Injectable()
|
|
134
|
+
export class ParseIntPipe implements PipeTransform<string, number> {
|
|
135
|
+
transform(value: string, metadata: ArgumentMetadata): number {
|
|
136
|
+
const val = parseInt(value, 10);
|
|
137
|
+
if (isNaN(val)) {
|
|
138
|
+
throw new BadRequestException('Validation failed');
|
|
139
|
+
}
|
|
140
|
+
return val;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Global Pipes
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
async function bootstrap() {
|
|
149
|
+
const app = await NestFactory.create(AppModule);
|
|
150
|
+
app.useGlobalPipes(new ValidationPipe());
|
|
151
|
+
await app.listen(3000);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Or via module:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { Module } from '@nestjs/common';
|
|
159
|
+
import { APP_PIPE } from '@nestjs/core';
|
|
160
|
+
|
|
161
|
+
@Module({
|
|
162
|
+
providers: [
|
|
163
|
+
{
|
|
164
|
+
provide: APP_PIPE,
|
|
165
|
+
useClass: ValidationPipe,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
})
|
|
169
|
+
export class AppModule {}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Default Values
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
@Get()
|
|
176
|
+
async findAll(
|
|
177
|
+
@Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean,
|
|
178
|
+
@Query('page', new DefaultValuePipe(0), ParseIntPipe) page: number,
|
|
179
|
+
) {
|
|
180
|
+
return this.catsService.findAll({ activeOnly, page });
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Key Points
|
|
185
|
+
|
|
186
|
+
- Pipes run before route handlers
|
|
187
|
+
- Pipes can transform or validate data
|
|
188
|
+
- Use built-in `ValidationPipe` for DTO validation
|
|
189
|
+
- Pipes can be parameter, method, controller, or global scoped
|
|
190
|
+
- Pipes throw exceptions to stop execution
|
|
191
|
+
- Use `DefaultValuePipe` before `Parse*` pipes for optional parameters
|
|
192
|
+
|
|
193
|
+
<!--
|
|
194
|
+
Source references:
|
|
195
|
+
- https://docs.nestjs.com/pipes
|
|
196
|
+
- https://docs.nestjs.com/techniques/validation
|
|
197
|
+
-->
|