@elsikora/nestjs-crud-automator 1.11.0-dev.1 → 1.11.1-dev.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.
Files changed (54) hide show
  1. package/README.md +293 -300
  2. package/dist/cjs/class/api/subscriber/executor.class.d.ts +6 -2
  3. package/dist/cjs/class/api/subscriber/executor.class.js +32 -4
  4. package/dist/cjs/class/api/subscriber/executor.class.js.map +1 -1
  5. package/dist/cjs/decorator/api/function/create.decorator.js +9 -4
  6. package/dist/cjs/decorator/api/function/create.decorator.js.map +1 -1
  7. package/dist/cjs/decorator/api/function/delete.decorator.js +9 -4
  8. package/dist/cjs/decorator/api/function/delete.decorator.js.map +1 -1
  9. package/dist/cjs/decorator/api/function/get-list.decorator.js +9 -4
  10. package/dist/cjs/decorator/api/function/get-list.decorator.js.map +1 -1
  11. package/dist/cjs/decorator/api/function/get-many.decorator.js +9 -4
  12. package/dist/cjs/decorator/api/function/get-many.decorator.js.map +1 -1
  13. package/dist/cjs/decorator/api/function/get.decorator.js +9 -4
  14. package/dist/cjs/decorator/api/function/get.decorator.js.map +1 -1
  15. package/dist/cjs/decorator/api/function/update.decorator.js +9 -4
  16. package/dist/cjs/decorator/api/function/update.decorator.js.map +1 -1
  17. package/dist/cjs/factory/api/controller.factory.js +42 -17
  18. package/dist/cjs/factory/api/controller.factory.js.map +1 -1
  19. package/dist/cjs/interface/class/api/subscriber/error-execution-context.interface.d.ts +15 -0
  20. package/dist/cjs/interface/class/api/subscriber/execution-context.interface.d.ts +5 -1
  21. package/dist/cjs/interface/class/api/subscriber/function-error-execution-context.interface.d.ts +10 -0
  22. package/dist/cjs/interface/class/api/subscriber/function-execution-context.interface.d.ts +4 -0
  23. package/dist/cjs/interface/class/api/subscriber/function.interface.d.ts +13 -12
  24. package/dist/cjs/interface/class/api/subscriber/index.d.ts +3 -0
  25. package/dist/cjs/interface/class/api/subscriber/route-error-execution-context.interface.d.ts +10 -0
  26. package/dist/cjs/interface/class/api/subscriber/route-execution-context.interface.d.ts +4 -0
  27. package/dist/cjs/interface/class/api/subscriber/route.interface.d.ts +13 -12
  28. package/dist/esm/class/api/subscriber/executor.class.d.ts +6 -2
  29. package/dist/esm/class/api/subscriber/executor.class.js +32 -4
  30. package/dist/esm/class/api/subscriber/executor.class.js.map +1 -1
  31. package/dist/esm/decorator/api/function/create.decorator.js +9 -4
  32. package/dist/esm/decorator/api/function/create.decorator.js.map +1 -1
  33. package/dist/esm/decorator/api/function/delete.decorator.js +9 -4
  34. package/dist/esm/decorator/api/function/delete.decorator.js.map +1 -1
  35. package/dist/esm/decorator/api/function/get-list.decorator.js +9 -4
  36. package/dist/esm/decorator/api/function/get-list.decorator.js.map +1 -1
  37. package/dist/esm/decorator/api/function/get-many.decorator.js +9 -4
  38. package/dist/esm/decorator/api/function/get-many.decorator.js.map +1 -1
  39. package/dist/esm/decorator/api/function/get.decorator.js +9 -4
  40. package/dist/esm/decorator/api/function/get.decorator.js.map +1 -1
  41. package/dist/esm/decorator/api/function/update.decorator.js +9 -4
  42. package/dist/esm/decorator/api/function/update.decorator.js.map +1 -1
  43. package/dist/esm/factory/api/controller.factory.js +42 -17
  44. package/dist/esm/factory/api/controller.factory.js.map +1 -1
  45. package/dist/esm/interface/class/api/subscriber/error-execution-context.interface.d.ts +15 -0
  46. package/dist/esm/interface/class/api/subscriber/execution-context.interface.d.ts +5 -1
  47. package/dist/esm/interface/class/api/subscriber/function-error-execution-context.interface.d.ts +10 -0
  48. package/dist/esm/interface/class/api/subscriber/function-execution-context.interface.d.ts +4 -0
  49. package/dist/esm/interface/class/api/subscriber/function.interface.d.ts +13 -12
  50. package/dist/esm/interface/class/api/subscriber/index.d.ts +3 -0
  51. package/dist/esm/interface/class/api/subscriber/route-error-execution-context.interface.d.ts +10 -0
  52. package/dist/esm/interface/class/api/subscriber/route-execution-context.interface.d.ts +4 -0
  53. package/dist/esm/interface/class/api/subscriber/route.interface.d.ts +13 -12
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -11,8 +11,8 @@
11
11
  </a> <img src="https://img.shields.io/badge/npm-blue.svg?style=for-the-badge&logo=npm&logoColor=white" alt="npm"> <img src="https://img.shields.io/badge/typescript-blue.svg?style=for-the-badge&logo=typescript&logoColor=white" alt="typescript"> <img src="https://img.shields.io/badge/nestjs-red.svg?style=for-the-badge&logo=nestjs&logoColor=white" alt="nestjs"> <img src="https://img.shields.io/badge/swagger-green.svg?style=for-the-badge&logo=swagger&logoColor=white" alt="swagger"> <img src="https://img.shields.io/badge/license-blue.svg?style=for-the-badge&logo=license&logoColor=white" alt="license"> <img src="https://img.shields.io/badge/version-1.6.2-brightgreen.svg?style=for-the-badge&logo=v&logoColor=white" alt="version-1.6.2">
12
12
  </p>
13
13
 
14
-
15
14
  ## 📚 Table of Contents
15
+
16
16
  - [Description](#-description)
17
17
  - [Features](#-features)
18
18
  - [Installation](#-installation)
@@ -25,13 +25,14 @@
25
25
  - [FAQ](#-faq)
26
26
  - [License](#-license)
27
27
 
28
-
29
28
  ## 📖 Description
29
+
30
30
  NestJS-Crud-Automator is a comprehensive library designed to eliminate repetitive code when building RESTful APIs with NestJS. It provides a suite of decorators, utilities, and validation tools that automatically generate controllers, DTOs, and service methods for handling Create, Read, Update, and Delete operations. This library significantly reduces development time by providing a declarative approach to API development. By simply describing your entity properties once, the library auto-generates all the necessary boilerplate code including Swagger documentation, validation rules, and transformation logic. Perfect for developers working on data-heavy applications who want to focus on business logic rather than repetitive CRUD implementation.
31
31
 
32
32
  The core philosophy of this library is built on four pillars: being **Declarative** (describe your API, don't code it), writing **Minimum Code** (drastically reduce boilerplate), ensuring **Flexibility** (override or extend any automated behavior), and guaranteeing **Type-Safety** (leverage TypeScript to prevent errors). It achieves this through real-time in-memory code generation, a heavy reliance on decorators for configuration, and smart conventions to reduce setup.
33
33
 
34
34
  ## 🚀 Features
35
+
35
36
  - ✨ **🏗️ Automatic generation of controllers, DTOs, and service methods for CRUD operations**
36
37
  - ✨ **📝 Comprehensive Swagger/OpenAPI documentation generation for all endpoints**
37
38
  - ✨ **✅ Built-in validation rules with class-validator integration**
@@ -49,6 +50,7 @@ The core philosophy of this library is built on four pillars: being **Declarativ
49
50
  - ✨ **Convention over Configuration:** Smart defaults for service and DTO naming to reduce boilerplate.
50
51
 
51
52
  ## 🛠 Installation
53
+
52
54
  ```bash
53
55
  ## Installation
54
56
 
@@ -82,6 +84,7 @@ npm install @nestjs/common @nestjs/swagger @nestjs/throttler typeorm class-trans
82
84
  ```
83
85
 
84
86
  ## 💡 Usage
87
+
85
88
  ## Basic Usage
86
89
 
87
90
  ### 1. Define Your Entity
@@ -89,57 +92,57 @@ npm install @nestjs/common @nestjs/swagger @nestjs/throttler typeorm class-trans
89
92
  First, define your entity with the `ApiPropertyDescribe` decorators to provide metadata for CRUD generation:
90
93
 
91
94
  ```typescript
92
- import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
93
- import { ApiPropertyDescribe, EApiPropertyDescribeType, EApiPropertyStringType, EApiPropertyDateIdentifier, EApiPropertyDateType } from '@elsikora/nestjs-crud-automator';
95
+ import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
96
+ import { ApiPropertyDescribe, EApiPropertyDescribeType, EApiPropertyStringType, EApiPropertyDateIdentifier, EApiPropertyDateType } from "@elsikora/nestjs-crud-automator";
94
97
 
95
- @Entity('users')
98
+ @Entity("users")
96
99
  export class UserEntity {
97
- @PrimaryGeneratedColumn('uuid')
98
- @ApiPropertyDescribe({
99
- type: EApiPropertyDescribeType.UUID,
100
- description: 'User unique identifier'
101
- })
102
- id: string;
103
-
104
- @Column()
105
- @ApiPropertyDescribe({
106
- type: EApiPropertyDescribeType.STRING,
107
- description: 'User name',
108
- format: EApiPropertyStringType.STRING,
109
- minLength: 3,
110
- maxLength: 50,
111
- pattern: '/^[a-zA-Z0-9_-]+$/',
112
- exampleValue: 'john_doe'
113
- })
114
- username: string;
115
-
116
- @Column()
117
- @ApiPropertyDescribe({
118
- type: EApiPropertyDescribeType.STRING,
119
- description: 'User email',
120
- format: EApiPropertyStringType.EMAIL,
121
- minLength: 5,
122
- maxLength: 255,
123
- pattern: '/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/',
124
- exampleValue: 'user@example.com'
125
- })
126
- email: string;
127
-
128
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
129
- @ApiPropertyDescribe({
130
- type: EApiPropertyDescribeType.DATE,
131
- identifier: EApiPropertyDateIdentifier.CREATED_AT,
132
- format: EApiPropertyDateType.DATE_TIME
133
- })
134
- createdAt: Date;
135
-
136
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' })
137
- @ApiPropertyDescribe({
138
- type: EApiPropertyDescribeType.DATE,
139
- identifier: EApiPropertyDateIdentifier.UPDATED_AT,
140
- format: EApiPropertyDateType.DATE_TIME
141
- })
142
- updatedAt: Date;
100
+ @PrimaryGeneratedColumn("uuid")
101
+ @ApiPropertyDescribe({
102
+ type: EApiPropertyDescribeType.UUID,
103
+ description: "User unique identifier",
104
+ })
105
+ id: string;
106
+
107
+ @Column()
108
+ @ApiPropertyDescribe({
109
+ type: EApiPropertyDescribeType.STRING,
110
+ description: "User name",
111
+ format: EApiPropertyStringType.STRING,
112
+ minLength: 3,
113
+ maxLength: 50,
114
+ pattern: "/^[a-zA-Z0-9_-]+$/",
115
+ exampleValue: "john_doe",
116
+ })
117
+ username: string;
118
+
119
+ @Column()
120
+ @ApiPropertyDescribe({
121
+ type: EApiPropertyDescribeType.STRING,
122
+ description: "User email",
123
+ format: EApiPropertyStringType.EMAIL,
124
+ minLength: 5,
125
+ maxLength: 255,
126
+ pattern: "/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/",
127
+ exampleValue: "user@example.com",
128
+ })
129
+ email: string;
130
+
131
+ @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP" })
132
+ @ApiPropertyDescribe({
133
+ type: EApiPropertyDescribeType.DATE,
134
+ identifier: EApiPropertyDateIdentifier.CREATED_AT,
135
+ format: EApiPropertyDateType.DATE_TIME,
136
+ })
137
+ createdAt: Date;
138
+
139
+ @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP", onUpdate: "CURRENT_TIMESTAMP" })
140
+ @ApiPropertyDescribe({
141
+ type: EApiPropertyDescribeType.DATE,
142
+ identifier: EApiPropertyDateIdentifier.UPDATED_AT,
143
+ format: EApiPropertyDateType.DATE_TIME,
144
+ })
145
+ updatedAt: Date;
143
146
  }
144
147
  ```
145
148
 
@@ -148,28 +151,28 @@ export class UserEntity {
148
151
  Create a service with the `ApiService` decorator to add CRUD operations:
149
152
 
150
153
  ```typescript
151
- import { Injectable } from '@nestjs/common';
152
- import { InjectRepository } from '@nestjs/typeorm';
153
- import { Repository } from 'typeorm';
154
- import { ApiService, ApiServiceBase } from '@elsikora/nestjs-crud-automator';
155
- import { UserEntity } from './user.entity';
154
+ import { Injectable } from "@nestjs/common";
155
+ import { InjectRepository } from "@nestjs/typeorm";
156
+ import { Repository } from "typeorm";
157
+ import { ApiService, ApiServiceBase } from "@elsikora/nestjs-crud-automator";
158
+ import { UserEntity } from "./user.entity";
156
159
 
157
160
  @Injectable()
158
161
  @ApiService<UserEntity>({
159
- entity: UserEntity
162
+ entity: UserEntity,
160
163
  })
161
164
  export class UserService extends ApiServiceBase<UserEntity> {
162
- constructor(
163
- @InjectRepository(UserEntity)
164
- public repository: Repository<UserEntity>
165
- ) {
166
- super();
167
- }
168
-
169
- // You can add custom methods here that go beyond basic CRUD
170
- async findByEmail(email: string): Promise<UserEntity | undefined> {
171
- return this.repository.findOne({ where: { email } });
172
- }
165
+ constructor(
166
+ @InjectRepository(UserEntity)
167
+ public repository: Repository<UserEntity>,
168
+ ) {
169
+ super();
170
+ }
171
+
172
+ // You can add custom methods here that go beyond basic CRUD
173
+ async findByEmail(email: string): Promise<UserEntity | undefined> {
174
+ return this.repository.findOne({ where: { email } });
175
+ }
173
176
  }
174
177
  ```
175
178
 
@@ -178,41 +181,41 @@ export class UserService extends ApiServiceBase<UserEntity> {
178
181
  Create a controller with the `ApiController` decorator to generate all CRUD endpoints:
179
182
 
180
183
  ```typescript
181
- import { Controller, UseGuards } from '@nestjs/common';
182
- import { ApiController, EApiRouteType } from '@elsikora/nestjs-crud-automator';
183
- import { UserEntity } from './user.entity';
184
- import { UserService } from './user.service';
185
- import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
184
+ import { Controller, UseGuards } from "@nestjs/common";
185
+ import { ApiController, EApiRouteType } from "@elsikora/nestjs-crud-automator";
186
+ import { UserEntity } from "./user.entity";
187
+ import { UserService } from "./user.service";
188
+ import { JwtAuthGuard } from "../auth/guards/jwt-auth.guard";
186
189
 
187
- @Controller('users')
190
+ @Controller("users")
188
191
  @ApiController<UserEntity>({
189
- entity: UserEntity,
190
- name: 'Users',
191
- routes: {
192
- [EApiRouteType.CREATE]: {
193
- authentication: {
194
- guard: JwtAuthGuard,
195
- bearerStrategies: ['jwt']
196
- }
197
- },
198
- [EApiRouteType.UPDATE]: {
199
- authentication: {
200
- guard: JwtAuthGuard,
201
- bearerStrategies: ['jwt']
202
- }
203
- },
204
- [EApiRouteType.DELETE]: {
205
- authentication: {
206
- guard: JwtAuthGuard,
207
- bearerStrategies: ['jwt']
208
- }
209
- },
210
- [EApiRouteType.GET]: {},
211
- [EApiRouteType.GET_LIST]: {}
212
- }
192
+ entity: UserEntity,
193
+ name: "Users",
194
+ routes: {
195
+ [EApiRouteType.CREATE]: {
196
+ authentication: {
197
+ guard: JwtAuthGuard,
198
+ bearerStrategies: ["jwt"],
199
+ },
200
+ },
201
+ [EApiRouteType.UPDATE]: {
202
+ authentication: {
203
+ guard: JwtAuthGuard,
204
+ bearerStrategies: ["jwt"],
205
+ },
206
+ },
207
+ [EApiRouteType.DELETE]: {
208
+ authentication: {
209
+ guard: JwtAuthGuard,
210
+ bearerStrategies: ["jwt"],
211
+ },
212
+ },
213
+ [EApiRouteType.GET]: {},
214
+ [EApiRouteType.GET_LIST]: {},
215
+ },
213
216
  })
214
217
  export class UserController {
215
- constructor(public service: UserService) {}
218
+ constructor(public service: UserService) {}
216
219
  }
217
220
  ```
218
221
 
@@ -223,28 +226,28 @@ export class UserController {
223
226
  Add custom validators to your DTOs:
224
227
 
225
228
  ```typescript
226
- import { ApiController, EApiRouteType, EApiDtoType, AllOrNoneOfListedPropertiesValidator } from '@elsikora/nestjs-crud-automator';
229
+ import { ApiController, EApiRouteType, EApiDtoType, AllOrNoneOfListedPropertiesValidator } from "@elsikora/nestjs-crud-automator";
227
230
 
228
231
  @ApiController<UserEntity>({
229
- entity: UserEntity,
230
- name: 'Users',
231
- routes: {
232
- [EApiRouteType.CREATE]: {
233
- autoDto: {
234
- [EApiDtoType.BODY]: {
235
- validators: [
236
- {
237
- constraintClass: AllOrNoneOfListedPropertiesValidator,
238
- options: ['firstName', 'lastName']
239
- }
240
- ]
241
- }
242
- }
243
- }
244
- }
232
+ entity: UserEntity,
233
+ name: "Users",
234
+ routes: {
235
+ [EApiRouteType.CREATE]: {
236
+ autoDto: {
237
+ [EApiDtoType.BODY]: {
238
+ validators: [
239
+ {
240
+ constraintClass: AllOrNoneOfListedPropertiesValidator,
241
+ options: ["firstName", "lastName"],
242
+ },
243
+ ],
244
+ },
245
+ },
246
+ },
247
+ },
245
248
  })
246
249
  export class UserController {
247
- constructor(public service: UserService) {}
250
+ constructor(public service: UserService) {}
248
251
  }
249
252
  ```
250
253
 
@@ -253,30 +256,30 @@ export class UserController {
253
256
  Automatically transform request data:
254
257
 
255
258
  ```typescript
256
- import { ApiController, EApiRouteType, EApiDtoType, EApiControllerRequestTransformerType, TRANSFORMER_VALUE_DTO_CONSTANT } from '@elsikora/nestjs-crud-automator';
259
+ import { ApiController, EApiRouteType, EApiDtoType, EApiControllerRequestTransformerType, TRANSFORMER_VALUE_DTO_CONSTANT } from "@elsikora/nestjs-crud-automator";
257
260
 
258
261
  @ApiController<UserEntity>({
259
- entity: UserEntity,
260
- name: 'Users',
261
- routes: {
262
- [EApiRouteType.CREATE]: {
263
- request: {
264
- transformers: {
265
- [EApiDtoType.BODY]: [
266
- {
267
- key: 'createdBy',
268
- type: EApiControllerRequestTransformerType.DYNAMIC,
269
- value: TRANSFORMER_VALUE_DTO_CONSTANT.AUTHORIZED_ENTITY,
270
- shouldSetValueEvenIfMissing: true
271
- }
272
- ]
273
- }
274
- }
275
- }
276
- }
262
+ entity: UserEntity,
263
+ name: "Users",
264
+ routes: {
265
+ [EApiRouteType.CREATE]: {
266
+ request: {
267
+ transformers: {
268
+ [EApiDtoType.BODY]: [
269
+ {
270
+ key: "createdBy",
271
+ type: EApiControllerRequestTransformerType.DYNAMIC,
272
+ value: TRANSFORMER_VALUE_DTO_CONSTANT.AUTHORIZED_ENTITY,
273
+ shouldSetValueEvenIfMissing: true,
274
+ },
275
+ ],
276
+ },
277
+ },
278
+ },
279
+ },
277
280
  })
278
281
  export class UserController {
279
- constructor(public service: UserService) {}
282
+ constructor(public service: UserService) {}
280
283
  }
281
284
  ```
282
285
 
@@ -285,34 +288,34 @@ export class UserController {
285
288
  Automatically load related entities:
286
289
 
287
290
  ```typescript
288
- import { ApiController, EApiRouteType, EApiControllerLoadRelationsStrategy } from '@elsikora/nestjs-crud-automator';
291
+ import { ApiController, EApiRouteType, EApiControllerLoadRelationsStrategy } from "@elsikora/nestjs-crud-automator";
289
292
 
290
293
  @ApiController<PostEntity>({
291
- entity: PostEntity,
292
- name: 'Posts',
293
- routes: {
294
- [EApiRouteType.GET]: {
295
- request: {
296
- relations: {
297
- shouldLoadRelations: true,
298
- relationsLoadStrategy: EApiControllerLoadRelationsStrategy.AUTO,
299
- servicesLoadStrategy: EApiControllerLoadRelationsStrategy.AUTO,
300
- shouldForceAllServicesToBeSpecified: false,
301
- relationsToLoad: ['author', 'comments']
302
- }
303
- },
304
- response: {
305
- relations: ['author', 'comments']
306
- }
307
- }
308
- }
294
+ entity: PostEntity,
295
+ name: "Posts",
296
+ routes: {
297
+ [EApiRouteType.GET]: {
298
+ request: {
299
+ relations: {
300
+ shouldLoadRelations: true,
301
+ relationsLoadStrategy: EApiControllerLoadRelationsStrategy.AUTO,
302
+ servicesLoadStrategy: EApiControllerLoadRelationsStrategy.AUTO,
303
+ shouldForceAllServicesToBeSpecified: false,
304
+ relationsToLoad: ["author", "comments"],
305
+ },
306
+ },
307
+ response: {
308
+ relations: ["author", "comments"],
309
+ },
310
+ },
311
+ },
309
312
  })
310
313
  export class PostController {
311
- constructor(
312
- public service: PostService,
313
- public authorService: UserService,
314
- public commentsService: CommentService
315
- ) {}
314
+ constructor(
315
+ public service: PostService,
316
+ public authorService: UserService,
317
+ public commentsService: CommentService,
318
+ ) {}
316
319
  }
317
320
  ```
318
321
 
@@ -321,31 +324,31 @@ export class PostController {
321
324
  Use custom DTOs instead of auto-generated ones:
322
325
 
323
326
  ```typescript
324
- import { ApiController, EApiRouteType } from '@elsikora/nestjs-crud-automator';
325
- import { CreateUserDto } from './dto/create-user.dto';
326
- import { UpdateUserDto } from './dto/update-user.dto';
327
- import { UserResponseDto } from './dto/user-response.dto';
327
+ import { ApiController, EApiRouteType } from "@elsikora/nestjs-crud-automator";
328
+ import { CreateUserDto } from "./dto/create-user.dto";
329
+ import { UpdateUserDto } from "./dto/update-user.dto";
330
+ import { UserResponseDto } from "./dto/user-response.dto";
328
331
 
329
332
  @ApiController<UserEntity>({
330
- entity: UserEntity,
331
- name: 'Users',
332
- routes: {
333
- [EApiRouteType.CREATE]: {
334
- dto: {
335
- body: CreateUserDto,
336
- response: UserResponseDto
337
- }
338
- },
339
- [EApiRouteType.UPDATE]: {
340
- dto: {
341
- body: UpdateUserDto,
342
- response: UserResponseDto
343
- }
344
- }
345
- }
333
+ entity: UserEntity,
334
+ name: "Users",
335
+ routes: {
336
+ [EApiRouteType.CREATE]: {
337
+ dto: {
338
+ body: CreateUserDto,
339
+ response: UserResponseDto,
340
+ },
341
+ },
342
+ [EApiRouteType.UPDATE]: {
343
+ dto: {
344
+ body: UpdateUserDto,
345
+ response: UserResponseDto,
346
+ },
347
+ },
348
+ },
346
349
  })
347
350
  export class UserController {
348
- constructor(public service: UserService) {}
351
+ constructor(public service: UserService) {}
349
352
  }
350
353
  ```
351
354
 
@@ -364,15 +367,16 @@ To simplify debugging and request tracing in complex systems, the library provid
364
367
  This allows you to link a specific client request with the logs on the server, which is invaluable when investigating incidents.
365
368
 
366
369
  **Registration:** `main.ts`
370
+
367
371
  ```typescript
368
- import { CorrelationIDResponseBodyInterceptor } from '@elsikora/nestjs-crud-automator';
372
+ import { CorrelationIDResponseBodyInterceptor } from "@elsikora/nestjs-crud-automator";
369
373
 
370
374
  async function bootstrap() {
371
- const app = await NestFactory.create(AppModule);
372
- // ...
373
- app.useGlobalInterceptors(new CorrelationIDResponseBodyInterceptor());
374
- // ...
375
- await app.listen(3000);
375
+ const app = await NestFactory.create(AppModule);
376
+ // ...
377
+ app.useGlobalInterceptors(new CorrelationIDResponseBodyInterceptor());
378
+ // ...
379
+ await app.listen(3000);
376
380
  }
377
381
  ```
378
382
 
@@ -380,59 +384,59 @@ async function bootstrap() {
380
384
 
381
385
  This is the most powerful feature for extending the default behavior. It allows you to "subscribe" to events in the CRUD request lifecycle and execute your code before, after, or in case of an error in the main operation. This is an ideal solution for tasks such as:
382
386
 
383
- - Auditing.
384
- - Sending notifications.
385
- - Complex, context-dependent validation.
386
- - Data enrichment before saving.
387
- - Custom error handling.
387
+ - Auditing.
388
+ - Sending notifications.
389
+ - Complex, context-dependent validation.
390
+ - Data enrichment before saving.
391
+ - Custom error handling.
388
392
 
389
393
  #### Enabling the Subscriber System
390
394
 
391
395
  To get the subscriber system working, you need to follow **three mandatory steps**:
392
396
 
393
- 1. **Import `ApiSubscriberModule`**: This module provides the `ApiSubscriberDiscoveryService`, which is responsible for discovering your subscribers. You need to import it into the root module of your application.
394
- `app.module.ts`
397
+ 1. **Import `ApiSubscriberModule`**: This module provides the `ApiSubscriberDiscoveryService`, which is responsible for discovering your subscribers. You need to import it into the root module of your application. `app.module.ts`
398
+
395
399
  ```typescript
396
400
  import { ApiSubscriberModule } from "@elsikora/nestjs-crud-automator";
397
401
 
398
402
  @Module({
399
- imports: [
400
- // ... other modules
401
- ApiSubscriberModule, // <--- IMPORTANT
402
- ],
403
- // ...
403
+ imports: [
404
+ // ... other modules
405
+ ApiSubscriberModule, // <--- IMPORTANT
406
+ ],
407
+ // ...
404
408
  })
405
409
  export class AppModule {}
406
410
  ```
407
411
 
408
412
  2. **Make the controller "observable"**: Add the `@ApiControllerObservable()` decorator to the controller class whose events you want to monitor.
413
+
409
414
  ```typescript
410
415
  import { ApiController, ApiControllerObservable } from "@elsikora/nestjs-crud-automator";
411
416
 
412
417
  @Controller("posts")
413
418
  @ApiController({
414
- /* ... */
419
+ /* ... */
415
420
  })
416
421
  @ApiControllerObservable() // <--- IMPORTANT
417
422
  export class PostController {
418
- /* ... */
423
+ /* ... */
419
424
  }
420
425
  ```
421
426
 
422
- 3. **Make the service "observable"**: Similarly, add the `@ApiServiceObservable()` decorator to the service class.
423
- ```typescript
424
- import { ApiService, ApiServiceBase, ApiServiceObservable } from "@elsikora/nestjs-crud-automator";
427
+ 3. **Make the service "observable"**: Similarly, add the `@ApiServiceObservable()` decorator to the service class. ```typescript import { ApiService, ApiServiceBase, ApiServiceObservable } from "@elsikora/nestjs-crud-automator";
425
428
 
426
- @Injectable()
427
- @ApiService({
428
- /* ... */
429
- })
430
- @ApiServiceObservable() // <--- IMPORTANT
431
- export class PostService extends ApiServiceBase<Post> {
432
- /* ... */
433
- }
434
- ```
435
- Without these steps, your subscriber classes will simply not be discovered and called.
429
+ @Injectable()
430
+ @ApiService({
431
+ /* ... */
432
+ })
433
+ @ApiServiceObservable() // <--- IMPORTANT
434
+ export class PostService extends ApiServiceBase<Post> {
435
+ /* ... */
436
+ }
437
+ ```
438
+
439
+ Without these steps, your subscriber classes will simply not be discovered and called.
436
440
 
437
441
  #### Two Levels of Interception
438
442
 
@@ -463,6 +467,7 @@ In case of an error at any stage, execution is interrupted, and the correspondin
463
467
  **Task**: Log which user created which post.
464
468
 
465
469
  1. **Create the subscriber:** `post-audit.subscriber.ts`
470
+
466
471
  ```typescript
467
472
  import { Injectable } from "@nestjs/common";
468
473
  import { ApiRouteSubscriber, ApiRouteSubscriberBase, IApiSubscriberRouteExecutionContext } from "@elsikora/nestjs-crud-automator";
@@ -472,18 +477,18 @@ In case of an error at any stage, execution is interrupted, and the correspondin
472
477
  @Injectable()
473
478
  @ApiRouteSubscriber({ entity: Post, priority: 10 }) // Specify entity and priority
474
479
  export class PostAuditSubscriber extends ApiRouteSubscriberBase<Post> {
475
- // Hook is called AFTER a post is successfully created in the controller
476
- async onAfterCreate(context: IApiSubscriberRouteExecutionContext<Post, Post, { user: User }>): Promise<Post> {
477
- const createdPost = context.result; // Result of the controller's operation
478
- const currentUser = context.data.user; // Immutable input data, including request.user
479
-
480
- if (createdPost && currentUser) {
481
- console.log(`AUDIT: User ${currentUser.id} created Post ${createdPost.id} with title "${createdPost.title}"`);
482
- }
483
-
484
- // We don't want to change the result, so we just return it
485
- return createdPost;
486
- }
480
+ // Hook is called AFTER a post is successfully created in the controller
481
+ async onAfterCreate(context: IApiSubscriberRouteExecutionContext<Post, Post, { user: User }>): Promise<Post> {
482
+ const createdPost = context.result; // Result of the controller's operation
483
+ const currentUser = context.data.user; // Immutable input data, including request.user
484
+
485
+ if (createdPost && currentUser) {
486
+ console.log(`AUDIT: User ${currentUser.id} created Post ${createdPost.id} with title "${createdPost.title}"`);
487
+ }
488
+
489
+ // We don't want to change the result, so we just return it
490
+ return createdPost;
491
+ }
487
492
  }
488
493
  ```
489
494
 
@@ -494,6 +499,7 @@ In case of an error at any stage, execution is interrupted, and the correspondin
494
499
  **Task**: When creating a post, automatically generate a `slug` from the `title` before saving it to the database.
495
500
 
496
501
  1. **Create the subscriber:** `post-slug.subscriber.ts`
502
+
497
503
  ```typescript
498
504
  import { Injectable } from "@nestjs/common";
499
505
  import { ApiFunctionSubscriber, ApiFunctionSubscriberBase, IApiSubscriberFunctionExecutionContext, TApiFunctionCreateProperties } from "@elsikora/nestjs-crud-automator";
@@ -503,19 +509,19 @@ In case of an error at any stage, execution is interrupted, and the correspondin
503
509
  @Injectable()
504
510
  @ApiFunctionSubscriber({ entity: Post })
505
511
  export class PostSlugSubscriber extends ApiFunctionSubscriberBase<Post> {
506
- // Hook is called BEFORE repository.save() is called
507
- async onBeforeCreate(context: IApiSubscriberFunctionExecutionContext<Post, TApiFunctionCreateProperties<Post>>): Promise<TApiFunctionCreateProperties<Post>> {
508
- const postData = context.result; // This is the object that will go into repository.save()
509
-
510
- if (postData.body.title) {
511
- // Modify the object, adding the slug
512
- postData.body.slug = slugify(postData.body.title, { lower: true, strict: true });
513
- console.log(`ENRICHMENT: Generated slug: ${postData.body.slug}`);
514
- }
515
-
516
- // Return the modified object, which will be saved
517
- return postData;
518
- }
512
+ // Hook is called BEFORE repository.save() is called
513
+ async onBeforeCreate(context: IApiSubscriberFunctionExecutionContext<Post, TApiFunctionCreateProperties<Post>>): Promise<TApiFunctionCreateProperties<Post>> {
514
+ const postData = context.result; // This is the object that will go into repository.save()
515
+
516
+ if (postData.body.title) {
517
+ // Modify the object, adding the slug
518
+ postData.body.slug = slugify(postData.body.title, { lower: true, strict: true });
519
+ console.log(`ENRICHMENT: Generated slug: ${postData.body.slug}`);
520
+ }
521
+
522
+ // Return the modified object, which will be saved
523
+ return postData;
524
+ }
519
525
  }
520
526
  ```
521
527
 
@@ -535,24 +541,19 @@ In case of an error at any stage, execution is interrupted, and the correspondin
535
541
  The library automatically generates Swagger/OpenAPI documentation for all endpoints. To enable it in your NestJS application:
536
542
 
537
543
  ```typescript
538
- import { NestFactory } from '@nestjs/core';
539
- import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
540
- import { AppModule } from './app.module';
544
+ import { NestFactory } from "@nestjs/core";
545
+ import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
546
+ import { AppModule } from "./app.module";
541
547
 
542
548
  async function bootstrap() {
543
- const app = await NestFactory.create(AppModule);
544
-
545
- const config = new DocumentBuilder()
546
- .setTitle('Your API')
547
- .setDescription('API description')
548
- .setVersion('1.0')
549
- .addBearerAuth()
550
- .build();
551
-
552
- const document = SwaggerModule.createDocument(app, config);
553
- SwaggerModule.setup('api', app, document);
554
-
555
- await app.listen(3000);
549
+ const app = await NestFactory.create(AppModule);
550
+
551
+ const config = new DocumentBuilder().setTitle("Your API").setDescription("API description").setVersion("1.0").addBearerAuth().build();
552
+
553
+ const document = SwaggerModule.createDocument(app, config);
554
+ SwaggerModule.setup("api", app, document);
555
+
556
+ await app.listen(3000);
556
557
  }
557
558
  bootstrap();
558
559
  ```
@@ -568,37 +569,39 @@ The library provides advanced filtering capabilities for list endpoints:
568
569
  This query would search for users with "john" in their username and created between Jan 1 and Dec 31, 2023.
569
570
 
570
571
  ## 🛣 Roadmap
572
+
571
573
  ## Roadmap
572
574
 
573
- | Task / Feature | Status |
574
- |---------------|--------|
575
- | Core CRUD operations | ✅ Done |
576
- | TypeORM integration | ✅ Done |
577
- | Swagger/OpenAPI documentation | ✅ Done |
578
- | Validation with class-validator | ✅ Done |
579
- | Transformation with class-transformer | ✅ Done |
580
- | Advanced filtering for GET_LIST operation | ✅ Done |
581
- | Authentication guard integration | ✅ Done |
582
- | Request/response transformers | ✅ Done |
583
- | Relation loading strategies | ✅ Done |
584
- | Custom validator integration | ✅ Done |
585
- | Pagination support | ✅ Done |
586
- | Error handling with standardized responses | ✅ Done |
587
- | Support for TypeScript decorators | ✅ Done |
588
- | Support for ESM and CommonJS modules | ✅ Done |
589
- | Subscriber System | ✅ Done |
590
- | MongoDB support | 🚧 In Progress |
591
- | GraphQL integration | 🚧 In Progress |
592
- | Support for soft deletes | 🚧 In Progress |
593
- | Role-based access control | 🚧 In Progress |
594
- | Cache integration | 🚧 In Progress |
595
- | Audit logging middleware | 🚧 In Progress |
575
+ | Task / Feature | Status |
576
+ | ------------------------------------------ | -------------- |
577
+ | Core CRUD operations | ✅ Done |
578
+ | TypeORM integration | ✅ Done |
579
+ | Swagger/OpenAPI documentation | ✅ Done |
580
+ | Validation with class-validator | ✅ Done |
581
+ | Transformation with class-transformer | ✅ Done |
582
+ | Advanced filtering for GET_LIST operation | ✅ Done |
583
+ | Authentication guard integration | ✅ Done |
584
+ | Request/response transformers | ✅ Done |
585
+ | Relation loading strategies | ✅ Done |
586
+ | Custom validator integration | ✅ Done |
587
+ | Pagination support | ✅ Done |
588
+ | Error handling with standardized responses | ✅ Done |
589
+ | Support for TypeScript decorators | ✅ Done |
590
+ | Support for ESM and CommonJS modules | ✅ Done |
591
+ | Subscriber System | ✅ Done |
592
+ | MongoDB support | 🚧 In Progress |
593
+ | GraphQL integration | 🚧 In Progress |
594
+ | Support for soft deletes | 🚧 In Progress |
595
+ | Role-based access control | 🚧 In Progress |
596
+ | Cache integration | 🚧 In Progress |
597
+ | Audit logging middleware | 🚧 In Progress |
596
598
  | Bulk operations (create many, update many) | 🚧 In Progress |
597
- | Query complexity analyzer | 🚧 In Progress |
598
- | Rate limiting enhancements | 🚧 In Progress |
599
- | Custom parameter decorators | 🚧 In Progress |
599
+ | Query complexity analyzer | 🚧 In Progress |
600
+ | Rate limiting enhancements | 🚧 In Progress |
601
+ | Custom parameter decorators | 🚧 In Progress |
600
602
 
601
603
  ## ❓ FAQ
604
+
602
605
  ## Frequently Asked Questions
603
606
 
604
607
  ### How does NestJS-Crud-Automator compare to @nestjsx/crud?
@@ -608,6 +611,7 @@ While @nestjsx/crud provides similar functionality, NestJS-Crud-Automator offers
608
611
  ### Can I customize the generated endpoints?
609
612
 
610
613
  Yes! The library provides multiple ways to customize your endpoints:
614
+
611
615
  1. You can disable specific routes
612
616
  2. Add authentication guards to specific routes
613
617
  3. Customize DTO validation and transformation
@@ -635,24 +639,13 @@ The core library doesn't include file upload functionality, but you can easily e
635
639
  Yes, as long as your repository follows the TypeORM Repository pattern, it will work with NestJS-Crud-Automator.
636
640
 
637
641
  ## 🔒 License
638
- This project is licensed under **MIT License
642
+
643
+ This project is licensed under \*\*MIT License
639
644
 
640
645
  Copyright (c) 2025 ElsiKora
641
646
 
642
- Permission is hereby granted, free of charge, to any person obtaining a copy
643
- of this software and associated documentation files (the "Software"), to deal
644
- in the Software without restriction, including without limitation the rights
645
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
646
- copies of the Software, and to permit persons to whom the Software is
647
- furnished to do so, subject to the following conditions:
648
-
649
- The above copyright notice and this permission notice shall be included in all
650
- copies or substantial portions of the Software.
651
-
652
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
653
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
654
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
655
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
656
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
657
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
658
- SOFTWARE.**.
647
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
648
+
649
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
650
+
651
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\*\*.