mongodb-dynamic-api 1.2.0-beta.7 → 1.2.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/CHANGELOG.md +16 -12
- package/README.md +249 -22
- package/package.json +4 -3
- package/src/builders/route-decorators.builder.d.ts +2 -1
- package/src/builders/route-decorators.builder.js +3 -2
- package/src/dynamic-api.module.d.ts +1 -1
- package/src/dynamic-api.module.js +16 -13
- package/src/helpers/format.helper.d.ts +1 -0
- package/src/helpers/format.helper.js +8 -0
- package/src/helpers/index.d.ts +5 -1
- package/src/helpers/index.js +5 -1
- package/src/helpers/route-description.helper.d.ts +3 -0
- package/src/helpers/route-description.helper.js +28 -0
- package/src/helpers/swagger-config.helper.d.ts +4 -0
- package/src/helpers/{config.helper.js → swagger-config.helper.js} +36 -21
- package/src/helpers/validation-config.helper.d.ts +3 -0
- package/src/helpers/validation-config.helper.js +8 -0
- package/src/helpers/versioning-config.helper.d.ts +3 -0
- package/src/helpers/versioning-config.helper.js +11 -0
- package/src/{helpers/config.helper.d.ts → interfaces/dynamic-api-swagger-options.type.d.ts} +23 -15
- package/src/interfaces/dynamic-api-swagger-options.type.js +2 -0
- package/src/interfaces/index.d.ts +1 -1
- package/src/interfaces/index.js +1 -1
- package/src/modules/create-many/create-many-controller.mixin.js +6 -6
- package/src/modules/create-many/create-many.helper.d.ts +1 -1
- package/src/modules/create-many/create-many.helper.js +7 -7
- package/src/modules/create-many/create-many.module.d.ts +2 -2
- package/src/modules/create-many/create-many.module.js +2 -2
- package/src/modules/create-one/create-one-controller.mixin.js +5 -5
- package/src/modules/create-one/create-one.helper.d.ts +1 -1
- package/src/modules/create-one/create-one.helper.js +7 -7
- package/src/modules/create-one/create-one.module.d.ts +2 -2
- package/src/modules/create-one/create-one.module.js +2 -2
- package/src/modules/delete-one/delete-one-controller.mixin.js +5 -5
- package/src/modules/delete-one/delete-one.helper.d.ts +1 -1
- package/src/modules/delete-one/delete-one.helper.js +7 -7
- package/src/modules/delete-one/delete-one.module.d.ts +2 -2
- package/src/modules/delete-one/delete-one.module.js +2 -2
- package/src/modules/duplicate-one/duplicate-one-controller.mixin.js +6 -6
- package/src/modules/duplicate-one/duplicate-one.helper.d.ts +1 -1
- package/src/modules/duplicate-one/duplicate-one.helper.js +7 -7
- package/src/modules/duplicate-one/duplicate-one.module.d.ts +2 -2
- package/src/modules/duplicate-one/duplicate-one.module.js +2 -2
- package/src/modules/get-many/get-many-controller.mixin.js +5 -5
- package/src/modules/get-many/get-many.helper.d.ts +1 -1
- package/src/modules/get-many/get-many.helper.js +7 -7
- package/src/modules/get-many/get-many.module.d.ts +2 -2
- package/src/modules/get-many/get-many.module.js +2 -2
- package/src/modules/get-one/get-one-controller.mixin.js +6 -6
- package/src/modules/get-one/get-one.helper.d.ts +1 -1
- package/src/modules/get-one/get-one.helper.js +7 -7
- package/src/modules/get-one/get-one.module.d.ts +2 -2
- package/src/modules/get-one/get-one.module.js +2 -2
- package/src/modules/replace-one/replace-one-controller.mixin.js +6 -6
- package/src/modules/replace-one/replace-one.helper.d.ts +1 -1
- package/src/modules/replace-one/replace-one.helper.js +7 -7
- package/src/modules/replace-one/replace-one.module.d.ts +2 -2
- package/src/modules/replace-one/replace-one.module.js +2 -2
- package/src/modules/update-one/update-one-controller.mixin.js +6 -6
- package/src/modules/update-one/update-one.helper.d.ts +1 -1
- package/src/modules/update-one/update-one.helper.js +7 -7
- package/src/modules/update-one/update-one.module.d.ts +2 -2
- package/src/modules/update-one/update-one.module.js +2 -2
- package/src/version.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/README/swagger.md +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
|
|
3
|
-
## [1.2.
|
|
3
|
+
## [1.2.1](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v1.2.0...v1.2.1) (2024-03-04)
|
|
4
4
|
|
|
5
|
-
## [1.2.0-beta.6](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/prerelease...1.2.0-beta.6) (2024-03-01)
|
|
6
5
|
|
|
7
|
-
## [1.2.0
|
|
6
|
+
## [1.2.0](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/v1.1.0...v1.2.0) (2024-03-03)
|
|
8
7
|
|
|
9
|
-
## [1.2.0-beta.4](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/prerelease...1.2.0-beta.4) (2024-02-29)
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
### api
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
* **api:** add default route description if not specified ([733b42a](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/733b42a6dab49c39370fdd4094b7f08288e54c5b))
|
|
14
12
|
|
|
15
|
-
##
|
|
13
|
+
## 1.1.0 (2024-03-03)
|
|
16
14
|
|
|
17
|
-
## [1.2.0-beta.0](https://github.com/MikeDev75015/mongodb-dynamic-api/compare/prerelease...1.2.0-beta.0) (2024-02-29)
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
### api
|
|
20
17
|
|
|
18
|
+
* **api:** add the possibility to enable the api uri versioning ([0f52917](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/0f529174ea583078bb136d2db484ef64b6aa6e49))
|
|
19
|
+
* **api:** correct CreateMany response type and body ([804b7d5](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/804b7d55fe2b8b515436b41fa338be75c5e030e2))
|
|
20
|
+
* **api:** make routes optional, add all routes automatically if not configured ([f17e2eb](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/f17e2ebdbbde8f05a5c80c404ffc1febf460bc20))
|
|
21
|
+
* **api:** set duplicate one body optional ([f24b2b9](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/f24b2b964e251fbb92acfc14222386fec3239dcb))
|
|
22
|
+
* **api:** add create-many module ([9ae72d5](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/9ae72d5dd7bda27423f96dd642d41eff31e75370))
|
|
21
23
|
|
|
22
|
-
### Features
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
### swagger
|
|
26
|
+
|
|
27
|
+
* **swagger:** add enable method ([5f3f865](https://github.com/MikeDev75015/mongodb-dynamic-api/commit/5f3f8656dc186e833d5c4792efacf9f0a2005afd))
|
|
28
|
+
|
|
25
29
|
|
|
26
|
-
##
|
|
30
|
+
## 1.0.0 (2024-02-27)
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
### Features
|
package/README.md
CHANGED
|
@@ -80,14 +80,18 @@ nest new --strict your-project-name
|
|
|
80
80
|
```text
|
|
81
81
|
npm i -S mongodb-dynamic-api
|
|
82
82
|
```
|
|
83
|
+
**Basic Configuration**
|
|
84
|
+
|
|
85
|
+
- Add `DynamicApiModule.forRoot` to your `app.module.ts` and pass your **MongoDB connection string** to the method.
|
|
83
86
|
|
|
84
|
-
- Add DynamicApiModule to your app.module.ts and pass the MongoDB connection string to the `forRoot` method
|
|
85
87
|
```typescript
|
|
88
|
+
// app.module.ts
|
|
89
|
+
import { DynamicApiModule } from 'mongodb-dynamic-api';
|
|
90
|
+
|
|
86
91
|
@Module({
|
|
87
92
|
imports: [
|
|
88
|
-
// ...
|
|
89
93
|
DynamicApiModule.forRoot(
|
|
90
|
-
// <-
|
|
94
|
+
'mongodb://127.0.0.1:27017/dynamic-api-db', // <- replace by your own connection string
|
|
91
95
|
),
|
|
92
96
|
// ...
|
|
93
97
|
],
|
|
@@ -96,12 +100,20 @@ npm i -S mongodb-dynamic-api
|
|
|
96
100
|
})
|
|
97
101
|
export class AppModule {}
|
|
98
102
|
```
|
|
103
|
+
**Basic usage**
|
|
104
|
+
|
|
105
|
+
- Ok, now let's add our first content with just 2 files. It will be a simple `User` with a `name` and an `email` field.
|
|
106
|
+
- We use the `@Schema` and `@Prop` decorators from the `@nestjs/mongoose` package to define our MongoDB model.
|
|
107
|
+
- You must extend the `BaseEntity` (or `SoftDeletableEntity`) class from the `mongodb-dynamic-api` package **for all your collection models**.
|
|
108
|
+
- Just create a new file `user.ts` and add the following code.
|
|
99
109
|
|
|
100
|
-
- Ok, now let's add our first content. This content will be a simple `User` with a `name` and an `email` field.
|
|
101
110
|
```typescript
|
|
102
|
-
// user.ts
|
|
111
|
+
// users/user.ts
|
|
112
|
+
import { Prop, Schema } from '@nestjs/mongoose';
|
|
113
|
+
import { BaseEntity } from 'mongodb-dynamic-api';
|
|
114
|
+
|
|
103
115
|
@Schema({ collection: 'users' })
|
|
104
|
-
export class User extends BaseEntity {
|
|
116
|
+
export class User extends BaseEntity {
|
|
105
117
|
@Prop({ type: String })
|
|
106
118
|
name: string;
|
|
107
119
|
|
|
@@ -109,11 +121,19 @@ export class User extends BaseEntity { // <- you must extend BaseEntity
|
|
|
109
121
|
email: string;
|
|
110
122
|
}
|
|
111
123
|
```
|
|
124
|
+
|
|
125
|
+
- Then we will use the `DynamicApiModule.forFeature` method to add the `User` content.
|
|
126
|
+
- We pass the `User` class to the `entity` property and specify the path `users` to the `controllerOptions` property.
|
|
127
|
+
- Create a new file `users.module.ts` and add the following code.
|
|
128
|
+
|
|
112
129
|
```typescript
|
|
113
|
-
// users.module.ts
|
|
130
|
+
// users/users.module.ts
|
|
131
|
+
import { DynamicApiModule } from 'mongodb-dynamic-api';
|
|
132
|
+
import { User } from './user';
|
|
133
|
+
|
|
114
134
|
@Module({
|
|
115
135
|
imports: [
|
|
116
|
-
DynamicApiModule.forFeature({
|
|
136
|
+
DynamicApiModule.forFeature({
|
|
117
137
|
entity: User,
|
|
118
138
|
controllerOptions: {
|
|
119
139
|
path: 'users',
|
|
@@ -123,13 +143,19 @@ export class User extends BaseEntity { // <- you must extend BaseEntity
|
|
|
123
143
|
})
|
|
124
144
|
export class UsersModule {}
|
|
125
145
|
```
|
|
146
|
+
|
|
147
|
+
- Last step, add the `UsersModule` to the **imports** in the `app.module.ts` after the `DynamicApiModule.forRoot` method.
|
|
148
|
+
|
|
126
149
|
```typescript
|
|
127
150
|
// app.module.ts
|
|
151
|
+
import { DynamicApiModule } from 'mongodb-dynamic-api';
|
|
152
|
+
import { UsersModule } from './users/users.module';
|
|
153
|
+
|
|
128
154
|
@Module({
|
|
129
155
|
imports: [
|
|
130
|
-
// ...
|
|
131
156
|
DynamicApiModule.forRoot('...'),
|
|
132
|
-
|
|
157
|
+
// ...
|
|
158
|
+
UsersModule,
|
|
133
159
|
],
|
|
134
160
|
controllers: [AppController],
|
|
135
161
|
providers: [AppService],
|
|
@@ -137,11 +163,18 @@ export class UsersModule {}
|
|
|
137
163
|
export class AppModule {}
|
|
138
164
|
```
|
|
139
165
|
|
|
140
|
-
**
|
|
166
|
+
**And that's all !** *You now have a fully functional CRUD API for the `User` content at the `/users` path.*
|
|
141
167
|
|
|
142
168
|
___
|
|
143
|
-
### Swagger (optional but recommended)
|
|
169
|
+
### [Swagger UI](https://docs.nestjs.com/openapi/introduction#document-options) (optional but strongly recommended)
|
|
170
|
+
`function enableDynamicAPISwagger(app: INestApplication, options?: DynamicAPISwaggerOptions): void`
|
|
171
|
+
|
|
172
|
+
**Configuration**
|
|
173
|
+
|
|
144
174
|
```typescript
|
|
175
|
+
// main.ts
|
|
176
|
+
import { enableDynamicAPISwagger } from 'mongodb-dynamic-api';
|
|
177
|
+
|
|
145
178
|
async function bootstrap() {
|
|
146
179
|
const app = await NestFactory.create(AppModule);
|
|
147
180
|
// ...
|
|
@@ -150,14 +183,22 @@ async function bootstrap() {
|
|
|
150
183
|
await app.listen(3000);
|
|
151
184
|
}
|
|
152
185
|
```
|
|
186
|
+
|
|
153
187
|
The `enableDynamicAPISwagger` function will automatically build the swagger documentation.
|
|
154
|
-
This method can be called with optional parameters to specify more documentation options.
|
|
188
|
+
<br>This method can be called with optional parameters to specify more documentation options.
|
|
189
|
+
<br>*See <strong>nestjs</strong> <a href="https://docs.nestjs.com/openapi/introduction#document-options" target="_blank">documentation</a> for more details.*
|
|
190
|
+
|
|
191
|
+
**Usage**
|
|
192
|
+
|
|
193
|
+
Add the `@ApiProperty` | `@ApiPropertyOptional` decorators to your class properties to have a better swagger documentation.
|
|
194
|
+
<br>Let's add an optional company field to the `User` class.
|
|
155
195
|
|
|
156
|
-
Do not forget to add the `@ApiProperty` decorator to your entity properties to have a better swagger documentation.
|
|
157
196
|
```typescript
|
|
158
|
-
// user.
|
|
197
|
+
// user.ts
|
|
198
|
+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
199
|
+
|
|
159
200
|
@Schema({ collection: 'users' })
|
|
160
|
-
export class
|
|
201
|
+
export class User extends BaseEntity {
|
|
161
202
|
@ApiProperty() // <- add this line
|
|
162
203
|
@Prop({ type: String })
|
|
163
204
|
name: string;
|
|
@@ -165,19 +206,114 @@ export class UserEntity extends BaseEntity {
|
|
|
165
206
|
@ApiProperty() // <- add this line
|
|
166
207
|
@Prop({ type: String })
|
|
167
208
|
email: string;
|
|
209
|
+
|
|
210
|
+
@ApiPropertyOptional() // <- add this line
|
|
211
|
+
@Prop({ type: String, required: false })
|
|
212
|
+
company?: string;
|
|
168
213
|
}
|
|
169
214
|
```
|
|
170
215
|
|
|
171
|
-
go to the swagger API path (default to `/
|
|
172
|
-
|
|
216
|
+
go to the swagger API path (default to `/dynamic-api`) and you will see the auto generated API
|
|
173
217
|
|
|
174
218
|

|
|
175
219
|
|
|
176
|
-
|
|
220
|
+
<a href="https://github.com/MikeDev75015/mongodb-dynamic-api/blob/develop/README/swagger.md" target="_blank">See more User API screenshots</a>
|
|
177
221
|
|
|
178
222
|
___
|
|
179
|
-
###
|
|
223
|
+
### [Validation](https://docs.nestjs.com/techniques/validation#using-the-built-in-validationpipe) (optional)
|
|
224
|
+
`function enableDynamicAPIValidation(app: INestApplication, options?: ValidationPipeOptions): void`
|
|
225
|
+
|
|
226
|
+
**Configuration**
|
|
227
|
+
|
|
180
228
|
```typescript
|
|
229
|
+
// main.ts
|
|
230
|
+
import { enableDynamicAPIValidation } from 'mongodb-dynamic-api';
|
|
231
|
+
|
|
232
|
+
async function bootstrap() {
|
|
233
|
+
const app = await NestFactory.create(AppModule);
|
|
234
|
+
// ...
|
|
235
|
+
enableDynamicAPIValidation(app); // <- add this line in your main.ts file
|
|
236
|
+
|
|
237
|
+
await app.listen(3000);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
The `enableDynamicAPIValidation` function allow to configure the pipe validation options for the API globally.
|
|
241
|
+
|
|
242
|
+
You can also define the pipe validation options in the `DynamicApiModule.forFeature` method, either in the controller options,
|
|
243
|
+
or in each route object defined in the routes property.
|
|
244
|
+
|
|
245
|
+
*If the options are specified in 2, the options specified in the route will have priority.*
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// users.module.ts
|
|
249
|
+
import { DynamicApiModule } from 'mongodb-dynamic-api';
|
|
250
|
+
import { User } from './user';
|
|
251
|
+
|
|
252
|
+
@Module({
|
|
253
|
+
imports: [
|
|
254
|
+
DynamicApiModule.forFeature({
|
|
255
|
+
entity: User,
|
|
256
|
+
controllerOptions: {
|
|
257
|
+
// ...
|
|
258
|
+
validationPipeOptions: { // <- in the controller options
|
|
259
|
+
transform: true,
|
|
260
|
+
whitelist: true,
|
|
261
|
+
forbidNonWhitelisted: true,
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
routes: [
|
|
265
|
+
{
|
|
266
|
+
type: 'DuplicateOne',
|
|
267
|
+
validationPipeOptions: { transform: true }, // <- in the route options
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
}),
|
|
271
|
+
],
|
|
272
|
+
})
|
|
273
|
+
export class UsersModule {}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Usage**
|
|
277
|
+
|
|
278
|
+
Use the `Class validator` <a href="https://github.com/typestack/class-validator?tab=readme-ov-file#validation-decorators" target="_blank">decorators</a> to validate your class properties.
|
|
279
|
+
<br>Let's add `IsEmail` decorator to the `email` field.
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// user.ts
|
|
283
|
+
import { IsEmail } from 'class-validator';
|
|
284
|
+
|
|
285
|
+
@Schema({ collection: 'users' })
|
|
286
|
+
export class User extends BaseEntity {
|
|
287
|
+
@ApiProperty()
|
|
288
|
+
@Prop({ type: String })
|
|
289
|
+
name: string;
|
|
290
|
+
|
|
291
|
+
@ApiProperty()
|
|
292
|
+
@IsEmail()
|
|
293
|
+
@Prop({ type: String })
|
|
294
|
+
email: string;
|
|
295
|
+
|
|
296
|
+
@ApiPropertyOptional()
|
|
297
|
+
@Prop({ type: String, required: false })
|
|
298
|
+
company?: string;
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Ok, now if you try to create a new user with an invalid email, you will get a `400 Bad Request` error.
|
|
303
|
+
|
|
304
|
+

|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
___
|
|
308
|
+
### [Versioning](https://docs.nestjs.com/techniques/versioning) (optional)
|
|
309
|
+
`function enableDynamicAPIVersioning(app: INestApplication, options?: VersioningOptions): void`
|
|
310
|
+
|
|
311
|
+
**Configuration**
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
// main.ts
|
|
315
|
+
import { enableDynamicAPIVersioning } from 'mongodb-dynamic-api';
|
|
316
|
+
|
|
181
317
|
async function bootstrap() {
|
|
182
318
|
const app = await NestFactory.create(AppModule);
|
|
183
319
|
// ...
|
|
@@ -186,5 +322,96 @@ async function bootstrap() {
|
|
|
186
322
|
await app.listen(3000);
|
|
187
323
|
}
|
|
188
324
|
```
|
|
189
|
-
|
|
190
|
-
|
|
325
|
+
|
|
326
|
+
The `enableDynamicAPIVersioning` function will automatically add versioning to the API.
|
|
327
|
+
<br>By default, it will use the <strong>URI versioning type</strong>.
|
|
328
|
+
<br>This method can be called with a second <strong>optional parameter</strong> to specify custom options.
|
|
329
|
+
<br>*See <strong>nestjs</strong> <a href="https://docs.nestjs.com/techniques/versioning" target="_blank">documentation</a> for more details.*
|
|
330
|
+
|
|
331
|
+
**Usage**
|
|
332
|
+
|
|
333
|
+
Pass the `version` property to the `controllerOptions` object or to the `route` object in the `DynamicApiModule.forFeature` method.
|
|
334
|
+
|
|
335
|
+
*If the version is specified in 2, the version specified in the route will have priority.*
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// create-one-user-v2.dto.ts
|
|
339
|
+
import { ApiProperty, ApiPropertyOptional, PickType } from '@nestjs/swagger';
|
|
340
|
+
import { IsOptional, IsString } from 'class-validator';
|
|
341
|
+
import { User } from './user';
|
|
342
|
+
|
|
343
|
+
export class CreateOneUserV2Dto extends PickType(User, ['email']) {
|
|
344
|
+
@ApiProperty()
|
|
345
|
+
@IsString()
|
|
346
|
+
fullName: string;
|
|
347
|
+
|
|
348
|
+
@ApiProperty()
|
|
349
|
+
@IsString()
|
|
350
|
+
phoneNumber: string;
|
|
351
|
+
|
|
352
|
+
@ApiPropertyOptional()
|
|
353
|
+
@IsString()
|
|
354
|
+
@IsOptional()
|
|
355
|
+
country?: string;
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// user-v2.presenter.ts
|
|
361
|
+
import { ApiProperty, ApiPropertyOptional, PickType } from '@nestjs/swagger';
|
|
362
|
+
import { User } from './user';
|
|
363
|
+
|
|
364
|
+
export class UserV2Presenter extends PickType(User, ['email']) {
|
|
365
|
+
@ApiProperty()
|
|
366
|
+
fullName: string;
|
|
367
|
+
|
|
368
|
+
@ApiProperty()
|
|
369
|
+
phoneNumber: string;
|
|
370
|
+
|
|
371
|
+
@ApiPropertyOptional()
|
|
372
|
+
country?: string;
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// users.module.ts
|
|
378
|
+
import { DynamicApiModule } from 'mongodb-dynamic-api';
|
|
379
|
+
import { User } from './user';
|
|
380
|
+
import { CreateOneUserV2Dto } from './create-one-user-v2.dto';
|
|
381
|
+
import { UserV2Presenter } from './user-v2.presenter';
|
|
382
|
+
|
|
383
|
+
@Module({
|
|
384
|
+
imports: [
|
|
385
|
+
DynamicApiModule.forFeature({
|
|
386
|
+
entity: User,
|
|
387
|
+
controllerOptions: {
|
|
388
|
+
path: 'users',
|
|
389
|
+
version: '1', // <- add this line
|
|
390
|
+
},
|
|
391
|
+
routes: [
|
|
392
|
+
{ type: 'GetMany' },
|
|
393
|
+
{ type: 'GetOne' },
|
|
394
|
+
{
|
|
395
|
+
type: 'CreateOne',
|
|
396
|
+
dTOs: {
|
|
397
|
+
body: CreateOneUserV2Dto,
|
|
398
|
+
presenter: UserV2Presenter,
|
|
399
|
+
},
|
|
400
|
+
version: '2', // <- add this line
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
}),
|
|
404
|
+
],
|
|
405
|
+
})
|
|
406
|
+
export class UsersModule {}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Great, now you have a versioned User API, and you can access it at the `/v1/users` and `/v2/users` path.
|
|
410
|
+
|
|
411
|
+

|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
___
|
|
415
|
+
|
|
416
|
+
More examples coming soon...
|
|
417
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb-dynamic-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Auto generated CRUD API for MongoDB using NestJS",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"main": "index.js",
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
"test:ci:junit": "jest --ci --runInBand --coverage --testResultsProcessor=jest-junit",
|
|
16
16
|
"test:ci:sonar": "jest --ci --runInBand --coverage --testResultsProcessor=jest-sonar-reporter",
|
|
17
17
|
"pre-release-tag": "git tag -f prerelease && git push -f origin prerelease",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"release-tag": "git tag -f release && git push -f origin release",
|
|
19
|
+
"auto-prerelease": "release-it --ci --preRelease=beta --no-git.requireUpstream --no-git.tag",
|
|
20
|
+
"auto-release": "release-it --ci --no-git.requireUpstream --no-git.tag",
|
|
20
21
|
"publish-prerelease": "npm publish ./dist --tag prerelease",
|
|
21
22
|
"publish-release": "npm publish ./dist --tag latest"
|
|
22
23
|
},
|
|
@@ -4,13 +4,14 @@ import { BaseEntity } from '../models';
|
|
|
4
4
|
declare class RouteDecoratorsBuilder<Entity extends BaseEntity> {
|
|
5
5
|
private readonly routeType;
|
|
6
6
|
private readonly entity;
|
|
7
|
+
private readonly version?;
|
|
7
8
|
private readonly description?;
|
|
8
9
|
private readonly param?;
|
|
9
10
|
private readonly query?;
|
|
10
11
|
private readonly body?;
|
|
11
12
|
private readonly presenter?;
|
|
12
13
|
private readonly responseRouteTypeIsArray;
|
|
13
|
-
constructor(routeType: RouteType, entity: Type<Entity>, description?: string, param?: Type, query?: Type, body?: Type, presenter?: Type);
|
|
14
|
+
constructor(routeType: RouteType, entity: Type<Entity>, version?: string, description?: string, param?: Type, query?: Type, body?: Type, presenter?: Type);
|
|
14
15
|
build(): MethodDecorator[];
|
|
15
16
|
private getRouteDecorators;
|
|
16
17
|
private getApiDecorators;
|
|
@@ -5,9 +5,10 @@ const common_1 = require("@nestjs/common");
|
|
|
5
5
|
const swagger_1 = require("@nestjs/swagger");
|
|
6
6
|
const lodash_1 = require("lodash");
|
|
7
7
|
class RouteDecoratorsBuilder {
|
|
8
|
-
constructor(routeType, entity, description, param, query, body, presenter) {
|
|
8
|
+
constructor(routeType, entity, version, description, param, query, body, presenter) {
|
|
9
9
|
this.routeType = routeType;
|
|
10
10
|
this.entity = entity;
|
|
11
|
+
this.version = version;
|
|
11
12
|
this.description = description;
|
|
12
13
|
this.param = param;
|
|
13
14
|
this.query = query;
|
|
@@ -50,7 +51,7 @@ class RouteDecoratorsBuilder {
|
|
|
50
51
|
getApiDecorators(paramKey) {
|
|
51
52
|
return [
|
|
52
53
|
(0, swagger_1.ApiOperation)({
|
|
53
|
-
operationId: `${(0, lodash_1.lowerFirst)(this.routeType)}${this.entity.name}`,
|
|
54
|
+
operationId: `${(0, lodash_1.lowerFirst)(this.routeType)}${this.entity.name}${this.version ? 'V' + this.version : ''}`,
|
|
54
55
|
summary: this.description ??
|
|
55
56
|
`${(0, lodash_1.upperFirst)((0, lodash_1.lowerCase)(this.routeType))} ${(0, lodash_1.lowerCase)(this.entity.name)}`,
|
|
56
57
|
}),
|
|
@@ -2,7 +2,7 @@ import { DynamicModule } from '@nestjs/common';
|
|
|
2
2
|
import { DynamicApiOptions } from './interfaces';
|
|
3
3
|
import { BaseEntity } from './models';
|
|
4
4
|
export declare class DynamicApiModule {
|
|
5
|
-
static connectionName
|
|
5
|
+
static readonly connectionName = "dynamic-api-connection";
|
|
6
6
|
static forRoot(uri: string): DynamicModule;
|
|
7
7
|
static forFeature<Entity extends BaseEntity>({ entity, controllerOptions: { path, apiTag, version: controllerVersion, validationPipeOptions: controllerValidationPipeOptions, }, routes, }: DynamicApiOptions<Entity>): DynamicModule;
|
|
8
8
|
}
|
|
@@ -10,8 +10,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.DynamicApiModule = void 0;
|
|
11
11
|
const common_1 = require("@nestjs/common");
|
|
12
12
|
const mongoose_1 = require("@nestjs/mongoose");
|
|
13
|
-
const lodash_1 = require("lodash");
|
|
14
13
|
const decorators_1 = require("./decorators");
|
|
14
|
+
const helpers_1 = require("./helpers");
|
|
15
15
|
const modules_1 = require("./modules");
|
|
16
16
|
let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
17
17
|
static forRoot(uri) {
|
|
@@ -41,24 +41,22 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
41
41
|
}
|
|
42
42
|
const databaseModule = mongoose_1.MongooseModule.forFeature([{ name: entity.name, schema }], DynamicApiModule_1.connectionName);
|
|
43
43
|
if (!routes.length) {
|
|
44
|
-
const contentName = (0, lodash_1.lowerCase)(entity.name);
|
|
45
44
|
routes = [
|
|
46
|
-
{ type: 'GetMany'
|
|
47
|
-
{ type: 'GetOne'
|
|
48
|
-
{ type: 'CreateMany'
|
|
49
|
-
{ type: 'CreateOne'
|
|
50
|
-
{ type: 'ReplaceOne'
|
|
51
|
-
{ type: 'UpdateOne'
|
|
52
|
-
{ type: 'DuplicateOne'
|
|
53
|
-
{ type: 'DeleteOne'
|
|
45
|
+
{ type: 'GetMany' },
|
|
46
|
+
{ type: 'GetOne' },
|
|
47
|
+
{ type: 'CreateMany' },
|
|
48
|
+
{ type: 'CreateOne' },
|
|
49
|
+
{ type: 'ReplaceOne' },
|
|
50
|
+
{ type: 'UpdateOne' },
|
|
51
|
+
{ type: 'DuplicateOne' },
|
|
52
|
+
{ type: 'DeleteOne' },
|
|
54
53
|
];
|
|
55
54
|
}
|
|
56
55
|
return {
|
|
57
56
|
module: DynamicApiModule_1,
|
|
58
57
|
imports: [
|
|
59
58
|
...routes
|
|
60
|
-
.map(({ type, description, version: routeVersion,
|
|
61
|
-
const version = routeVersion ?? controllerVersion;
|
|
59
|
+
.map(({ type, dTOs, description: routeDescription, version: routeVersion, validationPipeOptions: routeValidationPipeOptions, }) => {
|
|
62
60
|
let module;
|
|
63
61
|
switch (type) {
|
|
64
62
|
case 'CreateMany':
|
|
@@ -88,7 +86,12 @@ let DynamicApiModule = DynamicApiModule_1 = class DynamicApiModule {
|
|
|
88
86
|
default:
|
|
89
87
|
throw new Error(`Route for ${type} is not implemented`);
|
|
90
88
|
}
|
|
91
|
-
|
|
89
|
+
const description = routeDescription ?? (0, helpers_1.getDefaultRouteDescription)(type, entity.name);
|
|
90
|
+
const version = routeVersion ?? controllerVersion;
|
|
91
|
+
if (version?.match(/^\d+$/) === null) {
|
|
92
|
+
throw new Error(`Invalid version ${version} for ${type} route. Version must be a string that matches numeric format, e.g. 1, 2, 3, ..., 99.`);
|
|
93
|
+
}
|
|
94
|
+
return module.forFeature(databaseModule, entity, { path, apiTag }, { description, dTOs }, version, routeValidationPipeOptions ?? controllerValidationPipeOptions);
|
|
92
95
|
})
|
|
93
96
|
.filter((module) => module),
|
|
94
97
|
],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function pascalCase(str?: string): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pascalCase = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
function pascalCase(str) {
|
|
6
|
+
return str ? (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(str)) : undefined;
|
|
7
|
+
}
|
|
8
|
+
exports.pascalCase = pascalCase;
|
package/src/helpers/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './format.helper';
|
|
2
2
|
export * from './route-decorators.helper';
|
|
3
|
+
export * from './route-description.helper';
|
|
4
|
+
export * from './swagger-config.helper';
|
|
5
|
+
export * from './validation-config.helper';
|
|
6
|
+
export * from './versioning-config.helper';
|
package/src/helpers/index.js
CHANGED
|
@@ -14,5 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./format.helper"), exports);
|
|
18
18
|
__exportStar(require("./route-decorators.helper"), exports);
|
|
19
|
+
__exportStar(require("./route-description.helper"), exports);
|
|
20
|
+
__exportStar(require("./swagger-config.helper"), exports);
|
|
21
|
+
__exportStar(require("./validation-config.helper"), exports);
|
|
22
|
+
__exportStar(require("./versioning-config.helper"), exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDefaultRouteDescription = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
function getDefaultRouteDescription(routeType, entityName) {
|
|
6
|
+
const contentName = (0, lodash_1.lowerCase)(entityName);
|
|
7
|
+
switch (routeType) {
|
|
8
|
+
case 'CreateMany':
|
|
9
|
+
return `Create many ${contentName}`;
|
|
10
|
+
case 'CreateOne':
|
|
11
|
+
return `Create one ${contentName}`;
|
|
12
|
+
case 'DeleteOne':
|
|
13
|
+
return `Delete one ${contentName}`;
|
|
14
|
+
case 'DuplicateOne':
|
|
15
|
+
return `Duplicate one ${contentName}`;
|
|
16
|
+
case 'GetMany':
|
|
17
|
+
return `Get many ${contentName}`;
|
|
18
|
+
case 'GetOne':
|
|
19
|
+
return `Get one ${contentName} by id`;
|
|
20
|
+
case 'ReplaceOne':
|
|
21
|
+
return `Replace one ${contentName}`;
|
|
22
|
+
case 'UpdateOne':
|
|
23
|
+
return `Update one ${contentName}`;
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Route type "${routeType}" is not supported`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.getDefaultRouteDescription = getDefaultRouteDescription;
|