@anthonylzq/simba.js 2.0.5 → 3.0.0
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 +129 -52
- package/lib/index.js +29 -6
- package/lib/src/functions/{express.js → api.js} +1249 -651
- package/lib/src/functions/packageJson.js +4 -1
- package/lib/src/{installation.js → index.js} +16 -8
- package/package.json +14 -6
|
@@ -4,8 +4,12 @@ const exec = util.promisify(require('child_process').exec)
|
|
|
4
4
|
const writeFile = require('../utils/writeFile')
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
|
+
* Express api:
|
|
7
8
|
* src
|
|
8
9
|
* |- @types:
|
|
10
|
+
* |- |- custom:
|
|
11
|
+
* |- |- |- request: content, file
|
|
12
|
+
* |- |- |- response: content, file
|
|
9
13
|
* |- |- dto:
|
|
10
14
|
* |- |- |- user: content, file
|
|
11
15
|
* |- |- models:
|
|
@@ -27,9 +31,9 @@ const writeFile = require('../utils/writeFile')
|
|
|
27
31
|
* | | | |- user: content, file
|
|
28
32
|
* | | | |- index: content, file
|
|
29
33
|
* | | |- home: content, file
|
|
30
|
-
* | | |- user: content, file
|
|
31
34
|
* | | |- index: content, file
|
|
32
|
-
* | | |-
|
|
35
|
+
* | | |- user: content, file
|
|
36
|
+
* | |- response: content, file
|
|
33
37
|
* | |- router: content, file
|
|
34
38
|
* | |- server: content, file
|
|
35
39
|
* | |- index: content, file
|
|
@@ -49,12 +53,63 @@ const writeFile = require('../utils/writeFile')
|
|
|
49
53
|
* index.http: content, file
|
|
50
54
|
*/
|
|
51
55
|
|
|
56
|
+
/*
|
|
57
|
+
* Fastify api:
|
|
58
|
+
* src
|
|
59
|
+
* |- @types:
|
|
60
|
+
* |- |- dto:
|
|
61
|
+
* |- |- |- user: content, file
|
|
62
|
+
* |- |- models:
|
|
63
|
+
* |- |- |- user: content, file
|
|
64
|
+
* | |- index: content, file
|
|
65
|
+
* |- database:
|
|
66
|
+
* | |- mongo:
|
|
67
|
+
* | |- |- models:
|
|
68
|
+
* | |- |- |- index: content, file
|
|
69
|
+
* | |- |- |- user: content, file
|
|
70
|
+
* | |- |- queries:
|
|
71
|
+
* | |- |- |- index: content, file
|
|
72
|
+
* | |- |- |- user: content, file
|
|
73
|
+
* | |- |- index: content, file
|
|
74
|
+
* | |- index: content, file
|
|
75
|
+
* |- network:
|
|
76
|
+
* | |- routes:
|
|
77
|
+
* | | |- schemas:
|
|
78
|
+
* | | | |- user: content, file
|
|
79
|
+
* | | | |- index: content, file
|
|
80
|
+
* | | |- home: content, file
|
|
81
|
+
* | | |- user: content, file
|
|
82
|
+
* | | |- index: content, file
|
|
83
|
+
* | |- response: content, file
|
|
84
|
+
* | |- router: content, file
|
|
85
|
+
* | |- server: content, file
|
|
86
|
+
* | |- index: content, file
|
|
87
|
+
* |- services:
|
|
88
|
+
* | |- utils:
|
|
89
|
+
* | | |- messages:
|
|
90
|
+
* | | | |- user: content, file
|
|
91
|
+
* | | | |- index: content, file
|
|
92
|
+
* | | |- index: content, file
|
|
93
|
+
* | |- user: content, file
|
|
94
|
+
* | |- index: content, file
|
|
95
|
+
* |- .env: content, file
|
|
96
|
+
* |- index: content, file
|
|
97
|
+
* index.http: content, file
|
|
98
|
+
*/
|
|
99
|
+
|
|
52
100
|
/**
|
|
53
|
-
* @param {
|
|
54
|
-
* @param {String}
|
|
55
|
-
* @param {String}
|
|
101
|
+
* @param {Object} args
|
|
102
|
+
* @param {String} args.projectName
|
|
103
|
+
* @param {String} args.projectVersion
|
|
104
|
+
* @param {String} args.email
|
|
105
|
+
* @param {Boolean|undefined} args.fastify
|
|
56
106
|
*/
|
|
57
|
-
module.exports = async (
|
|
107
|
+
module.exports = async ({
|
|
108
|
+
projectName,
|
|
109
|
+
projectVersion,
|
|
110
|
+
email,
|
|
111
|
+
fastify = false
|
|
112
|
+
}) => {
|
|
58
113
|
const data = {
|
|
59
114
|
'@types': {
|
|
60
115
|
index: {
|
|
@@ -69,45 +124,18 @@ export {}
|
|
|
69
124
|
'@types/dto': {
|
|
70
125
|
user: {
|
|
71
126
|
content: `interface DtoUser {
|
|
72
|
-
id
|
|
73
|
-
lastName
|
|
74
|
-
name
|
|
127
|
+
id: string
|
|
128
|
+
lastName: string
|
|
129
|
+
name: string
|
|
75
130
|
}
|
|
76
131
|
`,
|
|
77
132
|
file: `${projectName}/src/@types/dto/user.d.ts`
|
|
78
133
|
}
|
|
79
134
|
},
|
|
80
|
-
'@types/custom': {
|
|
81
|
-
request: {
|
|
82
|
-
content: `type ExpressRequest = import('express').Request
|
|
83
|
-
|
|
84
|
-
interface CustomRequest extends ExpressRequest {
|
|
85
|
-
body: {
|
|
86
|
-
args?: DtoUser
|
|
87
|
-
}
|
|
88
|
-
// We can add custom headers via intersection, remember that for some reason
|
|
89
|
-
// headers must be in Snake-Pascal-Case
|
|
90
|
-
headers: import('http').IncomingHttpHeaders & {
|
|
91
|
-
'Custom-Header'?: string
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
`,
|
|
95
|
-
file: `${projectName}/src/@types/custom/request.d.ts`
|
|
96
|
-
},
|
|
97
|
-
response: {
|
|
98
|
-
content: `type ExpressResponse = import('express').Response
|
|
99
|
-
|
|
100
|
-
interface CustomResponse extends ExpressResponse {
|
|
101
|
-
newValue?: string
|
|
102
|
-
}
|
|
103
|
-
`,
|
|
104
|
-
file: `${projectName}/src/@types/custom/response.d.ts`
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
135
|
'@types/models': {
|
|
108
136
|
user: {
|
|
109
137
|
content: `interface IUser {
|
|
110
|
-
|
|
138
|
+
id: string
|
|
111
139
|
name: string
|
|
112
140
|
lastName: string
|
|
113
141
|
updatedAt: Date
|
|
@@ -154,14 +182,14 @@ const User = new Schema<IUser>(
|
|
|
154
182
|
createdAt: false,
|
|
155
183
|
updatedAt: true
|
|
156
184
|
},
|
|
185
|
+
versionKey: false,
|
|
157
186
|
toJSON: {
|
|
158
187
|
transform(_, ret) {
|
|
159
|
-
ret.id = ret._id
|
|
188
|
+
ret.id = ret._id.toString()
|
|
189
|
+
ret.updatedAt = ret.updatedAt.toISOString()
|
|
160
190
|
delete ret._id
|
|
161
191
|
delete ret.__v
|
|
162
|
-
delete ret.updatedAt
|
|
163
192
|
},
|
|
164
|
-
versionKey: false,
|
|
165
193
|
virtuals: true
|
|
166
194
|
}
|
|
167
195
|
}
|
|
@@ -180,12 +208,13 @@ export { UserModel }
|
|
|
180
208
|
file: `${projectName}/src/database/mongo/queries/index.ts`
|
|
181
209
|
},
|
|
182
210
|
user: {
|
|
183
|
-
content: `import { UserModel } from '
|
|
211
|
+
content: `import { UserModel } from '..'
|
|
184
212
|
|
|
185
213
|
const store = async (userData: DtoUser): Promise<IUser> => {
|
|
186
214
|
const user = new UserModel(userData)
|
|
215
|
+
await user.save()
|
|
187
216
|
|
|
188
|
-
return
|
|
217
|
+
return user.toJSON()
|
|
189
218
|
}
|
|
190
219
|
|
|
191
220
|
const remove = async (
|
|
@@ -199,15 +228,22 @@ const remove = async (
|
|
|
199
228
|
const get = async (
|
|
200
229
|
id: string | null = null
|
|
201
230
|
): Promise<IUser[] | IUser | null> => {
|
|
202
|
-
if (id)
|
|
231
|
+
if (id) {
|
|
232
|
+
const user = await UserModel.findById(id)
|
|
233
|
+
|
|
234
|
+
return user ? user.toJSON() : null
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const users = await UserModel.find({})
|
|
203
238
|
|
|
204
|
-
return
|
|
239
|
+
return users.map(u => u.toJSON())
|
|
205
240
|
}
|
|
206
241
|
|
|
207
242
|
const update = async (userData: DtoUser): Promise<IUser | null> => {
|
|
208
243
|
const { id, ...rest } = userData
|
|
244
|
+
const user = await UserModel.findByIdAndUpdate(id, rest, { new: true })
|
|
209
245
|
|
|
210
|
-
return
|
|
246
|
+
return user ? user.toJSON() : null
|
|
211
247
|
}
|
|
212
248
|
|
|
213
249
|
export { store, remove, get, update }
|
|
@@ -221,126 +257,353 @@ export { store, remove, get, update }
|
|
|
221
257
|
export * from './server'
|
|
222
258
|
`,
|
|
223
259
|
file: `${projectName}/src/network/index.ts`
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
services: {
|
|
263
|
+
index: {
|
|
264
|
+
content: "export * from './user'\n",
|
|
265
|
+
file: `${projectName}/src/services/index.ts`
|
|
224
266
|
},
|
|
225
|
-
|
|
226
|
-
content: `
|
|
227
|
-
error: boolean
|
|
228
|
-
message: unknown
|
|
229
|
-
res: CustomResponse
|
|
230
|
-
status: number
|
|
231
|
-
}
|
|
267
|
+
user: {
|
|
268
|
+
content: `import httpErrors from 'http-errors'
|
|
232
269
|
|
|
233
|
-
|
|
234
|
-
|
|
270
|
+
import { store, remove, get, update } from 'database'
|
|
271
|
+
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
272
|
+
|
|
273
|
+
type Process = {
|
|
274
|
+
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
235
275
|
}
|
|
236
276
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
file: `${projectName}/src/network/response.ts`
|
|
240
|
-
},
|
|
241
|
-
router: {
|
|
242
|
-
content: `import { Application, Response, Request, Router, NextFunction } from 'express'
|
|
243
|
-
import swaggerUi from 'swagger-ui-express'
|
|
244
|
-
import httpErrors from 'http-errors'
|
|
277
|
+
class UserService {
|
|
278
|
+
private _args: Partial<DtoUser> | null
|
|
245
279
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
280
|
+
constructor(args: Partial<DtoUser> | null = null) {
|
|
281
|
+
this._args = args
|
|
282
|
+
}
|
|
249
283
|
|
|
250
|
-
|
|
284
|
+
public process({ type }: Process): Promise<string | IUser[] | IUser> {
|
|
285
|
+
switch (type) {
|
|
286
|
+
case 'store':
|
|
287
|
+
return this._store()
|
|
288
|
+
case 'getAll':
|
|
289
|
+
return this._getAll()
|
|
290
|
+
case 'deleteAll':
|
|
291
|
+
return this._deleteAll()
|
|
292
|
+
case 'getOne':
|
|
293
|
+
return this._getOne()
|
|
294
|
+
case 'update':
|
|
295
|
+
return this._update()
|
|
296
|
+
case 'delete':
|
|
297
|
+
return this._delete()
|
|
298
|
+
default:
|
|
299
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
251
302
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
routers.forEach((router: Router): Application => app.use('/api', router))
|
|
303
|
+
private async _store(): Promise<IUser> {
|
|
304
|
+
try {
|
|
305
|
+
const result = await store(this._args as DtoUser)
|
|
256
306
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
})
|
|
261
|
-
app.use(
|
|
262
|
-
(
|
|
263
|
-
error: httpErrors.HttpError,
|
|
264
|
-
req: Request,
|
|
265
|
-
res: Response,
|
|
266
|
-
next: NextFunction
|
|
267
|
-
) => {
|
|
268
|
-
response({
|
|
269
|
-
error: true,
|
|
270
|
-
message: error.message,
|
|
271
|
-
res,
|
|
272
|
-
status: error.status
|
|
273
|
-
})
|
|
274
|
-
next()
|
|
307
|
+
return result
|
|
308
|
+
} catch (e) {
|
|
309
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
275
310
|
}
|
|
276
|
-
|
|
277
|
-
}
|
|
311
|
+
}
|
|
278
312
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
},
|
|
283
|
-
server: {
|
|
284
|
-
content: `import express from 'express'
|
|
285
|
-
import mongoose from 'mongoose'
|
|
286
|
-
import morgan from 'morgan'
|
|
313
|
+
private async _getAll(): Promise<IUser[]> {
|
|
314
|
+
try {
|
|
315
|
+
const users = (await get()) as IUser[]
|
|
287
316
|
|
|
288
|
-
|
|
317
|
+
return users
|
|
318
|
+
} catch (e) {
|
|
319
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
289
322
|
|
|
290
|
-
|
|
323
|
+
private async _deleteAll(): Promise<string> {
|
|
324
|
+
try {
|
|
325
|
+
const usersDeleted = (await remove()) as number
|
|
291
326
|
|
|
292
|
-
|
|
293
|
-
private _app: express.Application
|
|
294
|
-
private _connection: mongoose.Connection | undefined
|
|
327
|
+
if (usersDeleted >= 1) return MFU.ALL_USERS_DELETED
|
|
295
328
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
329
|
+
if (usersDeleted === 0)
|
|
330
|
+
throw new httpErrors.Conflict(EFU.NOTHING_TO_DELETE)
|
|
331
|
+
|
|
332
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
333
|
+
} catch (e) {
|
|
334
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
335
|
+
}
|
|
299
336
|
}
|
|
300
337
|
|
|
301
|
-
private
|
|
302
|
-
this.
|
|
303
|
-
this._app.use(morgan('dev'))
|
|
304
|
-
this._app.use(express.json())
|
|
305
|
-
this._app.use(express.urlencoded({ extended: false }))
|
|
306
|
-
this._app.use(
|
|
307
|
-
(
|
|
308
|
-
req: express.Request,
|
|
309
|
-
res: express.Response,
|
|
310
|
-
next: express.NextFunction
|
|
311
|
-
) => {
|
|
312
|
-
res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
|
|
313
|
-
res.header('Access-Control-Allow-Origin', '*')
|
|
314
|
-
res.header(
|
|
315
|
-
'Access-Control-Allow-Headers',
|
|
316
|
-
'Authorization, Content-Type'
|
|
317
|
-
)
|
|
318
|
-
next()
|
|
319
|
-
}
|
|
320
|
-
)
|
|
338
|
+
private async _getOne(): Promise<IUser> {
|
|
339
|
+
const { id } = this._args as DtoUser
|
|
321
340
|
|
|
322
|
-
|
|
341
|
+
try {
|
|
342
|
+
const user = (await get(id as string)) as IUser | null
|
|
343
|
+
|
|
344
|
+
if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
345
|
+
|
|
346
|
+
return user
|
|
347
|
+
} catch (e) {
|
|
348
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
349
|
+
}
|
|
323
350
|
}
|
|
324
351
|
|
|
325
|
-
private async
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
352
|
+
private async _update(): Promise<IUser> {
|
|
353
|
+
try {
|
|
354
|
+
const updatedUser = await update(this._args as DtoUser)
|
|
355
|
+
|
|
356
|
+
if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
357
|
+
|
|
358
|
+
return updatedUser
|
|
359
|
+
} catch (e) {
|
|
360
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
331
361
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
this.
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private async _delete(): Promise<string> {
|
|
365
|
+
const { id } = this._args as DtoUser
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
const deletedUser = await remove(id)
|
|
369
|
+
|
|
370
|
+
if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
371
|
+
|
|
372
|
+
return MFU.USER_DELETED
|
|
373
|
+
} catch (e) {
|
|
374
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export { UserService }
|
|
380
|
+
`,
|
|
381
|
+
file: `${projectName}/src/services/user.ts`
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
'services/utils': {
|
|
385
|
+
index: {
|
|
386
|
+
content: `import httpErrors from 'http-errors'
|
|
387
|
+
|
|
388
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
389
|
+
const errorHandling = (e: any, message?: string): never => {
|
|
390
|
+
console.error(e)
|
|
391
|
+
|
|
392
|
+
if (e instanceof httpErrors.HttpError) throw e
|
|
393
|
+
|
|
394
|
+
throw new httpErrors.InternalServerError(message ?? e.message)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export { errorHandling }
|
|
398
|
+
export * from './messages'
|
|
399
|
+
`,
|
|
400
|
+
file: `${projectName}/src/services/utils/index.ts`
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
'services/utils/messages': {
|
|
404
|
+
index: {
|
|
405
|
+
content: `enum GenericErrors {
|
|
406
|
+
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export { GenericErrors as GE }
|
|
410
|
+
export * from './user'
|
|
411
|
+
`,
|
|
412
|
+
file: `${projectName}/src/services/utils/messages/index.ts`
|
|
413
|
+
},
|
|
414
|
+
user: {
|
|
415
|
+
content: `enum ErrorForUser {
|
|
416
|
+
NOT_FOUND = 'The requested user does not exists',
|
|
417
|
+
NOTHING_TO_DELETE = 'There is no user to be deleted'
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
enum MessageForUser {
|
|
421
|
+
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
422
|
+
USER_DELETED = 'The requested user was successfully deleted'
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
426
|
+
`,
|
|
427
|
+
file: `${projectName}/src/services/utils/messages/user.ts`
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
test: {
|
|
431
|
+
index: {
|
|
432
|
+
content: `### Testing store a user
|
|
433
|
+
POST http://localhost:1996/api/users
|
|
434
|
+
Content-Type: application/json
|
|
435
|
+
|
|
436
|
+
{
|
|
437
|
+
"args": {
|
|
438
|
+
"lastName": "Lzq",
|
|
439
|
+
"name": "Anthony"
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
### Testing getAll users
|
|
444
|
+
GET http://localhost:1996/api/users
|
|
445
|
+
|
|
446
|
+
### Testing deleteAll users
|
|
447
|
+
DELETE http://localhost:1996/api/users
|
|
448
|
+
|
|
449
|
+
### Testing getOne user
|
|
450
|
+
GET http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
451
|
+
|
|
452
|
+
### Testing update user
|
|
453
|
+
PATCH http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
454
|
+
Content-Type: application/json
|
|
455
|
+
|
|
456
|
+
{
|
|
457
|
+
"args": {
|
|
458
|
+
"name": "Anthony",
|
|
459
|
+
"lastName": "Luzquiños"
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
### Testing delete user
|
|
464
|
+
DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
465
|
+
`,
|
|
466
|
+
file: `${projectName}/index.http`
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
'.env': {
|
|
470
|
+
content: `MONGO_URI = ${
|
|
471
|
+
process.env.LOCAL
|
|
472
|
+
? process.env.MONGO_URI
|
|
473
|
+
: `mongodb://mongo:mongo@mongo:27017/${projectName}`
|
|
474
|
+
}`,
|
|
475
|
+
file: `${projectName}/.env`
|
|
476
|
+
},
|
|
477
|
+
index: {
|
|
478
|
+
content: `import { Server } from './network'
|
|
479
|
+
|
|
480
|
+
Server.start()
|
|
481
|
+
`,
|
|
482
|
+
file: `${projectName}/src/index.ts`
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const expressData = {
|
|
487
|
+
network: {
|
|
488
|
+
response: {
|
|
489
|
+
content: `interface ResponseProps {
|
|
490
|
+
error: boolean
|
|
491
|
+
message: unknown
|
|
492
|
+
res: CustomResponse
|
|
493
|
+
status: number
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const response = ({ error, message, res, status }: ResponseProps): void => {
|
|
497
|
+
res.status(status).send({ error, message })
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export { response }
|
|
501
|
+
`,
|
|
502
|
+
file: `${projectName}/src/network/response.ts`
|
|
503
|
+
},
|
|
504
|
+
router: {
|
|
505
|
+
content: `import { Application, Response, Request, Router, NextFunction } from 'express'
|
|
506
|
+
import swaggerUi from 'swagger-ui-express'
|
|
507
|
+
import httpErrors from 'http-errors'
|
|
508
|
+
|
|
509
|
+
import { response } from './response'
|
|
510
|
+
import { Home, User } from './routes'
|
|
511
|
+
import { docs } from 'utils'
|
|
512
|
+
|
|
513
|
+
const routers = [User]
|
|
514
|
+
|
|
515
|
+
const applyRoutes = (app: Application): void => {
|
|
516
|
+
app.use('/', Home)
|
|
517
|
+
app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(docs))
|
|
518
|
+
routers.forEach((router: Router): Application => app.use('/api', router))
|
|
519
|
+
|
|
520
|
+
// Handling 404 error
|
|
521
|
+
app.use((req, res, next) => {
|
|
522
|
+
next(new httpErrors.NotFound('This route does not exists'))
|
|
523
|
+
})
|
|
524
|
+
app.use(
|
|
525
|
+
(
|
|
526
|
+
error: httpErrors.HttpError,
|
|
527
|
+
req: Request,
|
|
528
|
+
res: Response,
|
|
529
|
+
next: NextFunction
|
|
530
|
+
) => {
|
|
531
|
+
response({
|
|
532
|
+
error: true,
|
|
533
|
+
message: error.message,
|
|
534
|
+
res,
|
|
535
|
+
status: error.status
|
|
536
|
+
})
|
|
537
|
+
next()
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export { applyRoutes }
|
|
543
|
+
`,
|
|
544
|
+
file: `${projectName}/src/network/router.ts`
|
|
545
|
+
},
|
|
546
|
+
server: {
|
|
547
|
+
content: `import express from 'express'
|
|
548
|
+
import mongoose from 'mongoose'
|
|
549
|
+
import morgan from 'morgan'
|
|
550
|
+
|
|
551
|
+
import { applyRoutes } from './router'
|
|
552
|
+
|
|
553
|
+
const PORT = (process.env.PORT as string) || '1996'
|
|
554
|
+
|
|
555
|
+
class Server {
|
|
556
|
+
private _app: express.Application
|
|
557
|
+
private _connection: mongoose.Connection | undefined
|
|
558
|
+
|
|
559
|
+
constructor() {
|
|
560
|
+
this._app = express()
|
|
561
|
+
this._config()
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private _config() {
|
|
565
|
+
this._app.set('port', PORT)
|
|
566
|
+
this._app.use(morgan('dev'))
|
|
567
|
+
this._app.use(express.json())
|
|
568
|
+
this._app.use(express.urlencoded({ extended: false }))
|
|
569
|
+
this._app.use(
|
|
570
|
+
(
|
|
571
|
+
req: express.Request,
|
|
572
|
+
res: express.Response,
|
|
573
|
+
next: express.NextFunction
|
|
574
|
+
) => {
|
|
575
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
|
|
576
|
+
res.header('Access-Control-Allow-Origin', '*')
|
|
577
|
+
res.header(
|
|
578
|
+
'Access-Control-Allow-Headers',
|
|
579
|
+
'Authorization, Content-Type'
|
|
580
|
+
)
|
|
581
|
+
next()
|
|
582
|
+
}
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
applyRoutes(this._app)
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private async _mongo(): Promise<void> {
|
|
589
|
+
this._connection = mongoose.connection
|
|
590
|
+
const connection = {
|
|
591
|
+
keepAlive: true,
|
|
592
|
+
useNewUrlParser: true,
|
|
593
|
+
useUnifiedTopology: true
|
|
594
|
+
}
|
|
595
|
+
this._connection.on('connected', () => {
|
|
596
|
+
console.log('Mongo connection established.')
|
|
597
|
+
})
|
|
598
|
+
this._connection.on('reconnected', () => {
|
|
599
|
+
console.log('Mongo connection reestablished')
|
|
600
|
+
})
|
|
601
|
+
this._connection.on('disconnected', () => {
|
|
602
|
+
console.log('Mongo connection disconnected')
|
|
603
|
+
console.log('Trying to reconnected to Mongo...')
|
|
604
|
+
setTimeout(() => {
|
|
605
|
+
mongoose.connect(process.env.MONGO_URI as string, {
|
|
606
|
+
...connection,
|
|
344
607
|
connectTimeoutMS: 3000,
|
|
345
608
|
socketTimeoutMS: 3000
|
|
346
609
|
})
|
|
@@ -376,6 +639,33 @@ export { server as Server }
|
|
|
376
639
|
file: `${projectName}/src/network/server.ts`
|
|
377
640
|
}
|
|
378
641
|
},
|
|
642
|
+
'@types/custom': {
|
|
643
|
+
request: {
|
|
644
|
+
content: `type ExpressRequest = import('express').Request
|
|
645
|
+
|
|
646
|
+
interface CustomRequest extends ExpressRequest {
|
|
647
|
+
body: {
|
|
648
|
+
args?: DtoUser
|
|
649
|
+
}
|
|
650
|
+
// We can add custom headers via intersection, remember that for some reason
|
|
651
|
+
// headers must be in Snake-Pascal-Case
|
|
652
|
+
headers: import('http').IncomingHttpHeaders & {
|
|
653
|
+
'Custom-Header'?: string
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
`,
|
|
657
|
+
file: `${projectName}/src/@types/custom/request.d.ts`
|
|
658
|
+
},
|
|
659
|
+
response: {
|
|
660
|
+
content: `type ExpressResponse = import('express').Response
|
|
661
|
+
|
|
662
|
+
interface CustomResponse extends ExpressResponse {
|
|
663
|
+
newValue?: string
|
|
664
|
+
}
|
|
665
|
+
`,
|
|
666
|
+
file: `${projectName}/src/@types/custom/response.d.ts`
|
|
667
|
+
}
|
|
668
|
+
},
|
|
379
669
|
'network/routes': {
|
|
380
670
|
home: {
|
|
381
671
|
content: `import { Response, Request, Router } from 'express'
|
|
@@ -410,7 +700,7 @@ import { ValidationError } from 'joi'
|
|
|
410
700
|
|
|
411
701
|
import { response } from 'network/response'
|
|
412
702
|
import { UserService } from 'services/user'
|
|
413
|
-
import { idSchema, userSchema } from './schemas'
|
|
703
|
+
import { idSchema, userSchema, storeUserSchema } from './schemas'
|
|
414
704
|
|
|
415
705
|
const User = Router()
|
|
416
706
|
|
|
@@ -424,65 +714,12 @@ User.route('/users')
|
|
|
424
714
|
const {
|
|
425
715
|
body: { args }
|
|
426
716
|
} = req
|
|
427
|
-
const us = new UserService(args as DtoUser)
|
|
428
717
|
|
|
429
718
|
try {
|
|
719
|
+
await storeUserSchema.validateAsync(args)
|
|
720
|
+
const us = new UserService(args)
|
|
430
721
|
const result = await us.process({ type: 'store' })
|
|
431
722
|
response({ error: false, message: result, res, status: 201 })
|
|
432
|
-
} catch (e) {
|
|
433
|
-
next(e)
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
)
|
|
437
|
-
.get(
|
|
438
|
-
async (
|
|
439
|
-
req: CustomRequest,
|
|
440
|
-
res: CustomResponse,
|
|
441
|
-
next: NextFunction
|
|
442
|
-
): Promise<void> => {
|
|
443
|
-
const us = new UserService()
|
|
444
|
-
|
|
445
|
-
try {
|
|
446
|
-
const result = await us.process({ type: 'getAll' })
|
|
447
|
-
response({ error: false, message: result, res, status: 200 })
|
|
448
|
-
} catch (e) {
|
|
449
|
-
next(e)
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
)
|
|
453
|
-
.delete(
|
|
454
|
-
async (
|
|
455
|
-
req: CustomRequest,
|
|
456
|
-
res: CustomResponse,
|
|
457
|
-
next: NextFunction
|
|
458
|
-
): Promise<void> => {
|
|
459
|
-
const us = new UserService()
|
|
460
|
-
|
|
461
|
-
try {
|
|
462
|
-
const result = await us.process({ type: 'deleteAll' })
|
|
463
|
-
response({ error: false, message: result, res, status: 200 })
|
|
464
|
-
} catch (e) {
|
|
465
|
-
next(e)
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
)
|
|
469
|
-
|
|
470
|
-
User.route('/user/:id')
|
|
471
|
-
.get(
|
|
472
|
-
async (
|
|
473
|
-
req: CustomRequest,
|
|
474
|
-
res: CustomResponse,
|
|
475
|
-
next: NextFunction
|
|
476
|
-
): Promise<void> => {
|
|
477
|
-
const {
|
|
478
|
-
params: { id }
|
|
479
|
-
} = req
|
|
480
|
-
|
|
481
|
-
try {
|
|
482
|
-
await idSchema.validateAsync(id)
|
|
483
|
-
const us = new UserService({ id } as DtoUser)
|
|
484
|
-
const result = await us.process({ type: 'getOne' })
|
|
485
|
-
response({ error: false, message: result, res, status: 200 })
|
|
486
723
|
} catch (e) {
|
|
487
724
|
if (e instanceof ValidationError)
|
|
488
725
|
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
@@ -491,30 +728,18 @@ User.route('/user/:id')
|
|
|
491
728
|
}
|
|
492
729
|
}
|
|
493
730
|
)
|
|
494
|
-
.
|
|
731
|
+
.get(
|
|
495
732
|
async (
|
|
496
733
|
req: CustomRequest,
|
|
497
734
|
res: CustomResponse,
|
|
498
735
|
next: NextFunction
|
|
499
736
|
): Promise<void> => {
|
|
500
|
-
const
|
|
501
|
-
body: { args },
|
|
502
|
-
params: { id }
|
|
503
|
-
} = req
|
|
504
|
-
const user: DtoUser = {
|
|
505
|
-
id,
|
|
506
|
-
...args
|
|
507
|
-
}
|
|
737
|
+
const us = new UserService()
|
|
508
738
|
|
|
509
739
|
try {
|
|
510
|
-
await
|
|
511
|
-
const us = new UserService(user)
|
|
512
|
-
const result = await us.process({ type: 'update' })
|
|
740
|
+
const result = await us.process({ type: 'getAll' })
|
|
513
741
|
response({ error: false, message: result, res, status: 200 })
|
|
514
742
|
} catch (e) {
|
|
515
|
-
if (e instanceof ValidationError)
|
|
516
|
-
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
517
|
-
|
|
518
743
|
next(e)
|
|
519
744
|
}
|
|
520
745
|
}
|
|
@@ -525,259 +750,126 @@ User.route('/user/:id')
|
|
|
525
750
|
res: CustomResponse,
|
|
526
751
|
next: NextFunction
|
|
527
752
|
): Promise<void> => {
|
|
528
|
-
const
|
|
529
|
-
params: { id }
|
|
530
|
-
} = req
|
|
531
|
-
|
|
532
|
-
try {
|
|
533
|
-
await idSchema.validateAsync(id)
|
|
534
|
-
const us = new UserService({ id } as DtoUser)
|
|
535
|
-
const result = await us.process({ type: 'delete' })
|
|
536
|
-
response({ error: false, message: result, res, status: 200 })
|
|
537
|
-
} catch (e) {
|
|
538
|
-
if (e instanceof ValidationError)
|
|
539
|
-
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
540
|
-
|
|
541
|
-
next(e)
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
export { User }
|
|
547
|
-
`,
|
|
548
|
-
file: `${projectName}/src/network/routes/user.ts`
|
|
549
|
-
}
|
|
550
|
-
},
|
|
551
|
-
'network/routes/schemas': {
|
|
552
|
-
index: {
|
|
553
|
-
content: `import Joi from 'joi'
|
|
554
|
-
|
|
555
|
-
const idSchema = Joi.string().length(24).required()
|
|
556
|
-
|
|
557
|
-
export { idSchema }
|
|
558
|
-
export * from './user'
|
|
559
|
-
`,
|
|
560
|
-
file: `${projectName}/src/network/routes/schemas/index.ts`
|
|
561
|
-
},
|
|
562
|
-
user: {
|
|
563
|
-
content: `import Joi from 'joi'
|
|
564
|
-
|
|
565
|
-
const userSchema = Joi.object().keys({
|
|
566
|
-
id: Joi.string().length(24).required(),
|
|
567
|
-
lastName: Joi.string().required(),
|
|
568
|
-
name: Joi.string().required()
|
|
569
|
-
})
|
|
570
|
-
|
|
571
|
-
export { userSchema }
|
|
572
|
-
`,
|
|
573
|
-
file: `${projectName}/src/network/routes/schemas/user.ts`
|
|
574
|
-
}
|
|
575
|
-
},
|
|
576
|
-
services: {
|
|
577
|
-
index: {
|
|
578
|
-
content: "export * from './user'\n",
|
|
579
|
-
file: `${projectName}/src/services/index.ts`
|
|
580
|
-
},
|
|
581
|
-
user: {
|
|
582
|
-
content: `import httpErrors from 'http-errors'
|
|
583
|
-
|
|
584
|
-
import { store, remove, get, update } from 'database'
|
|
585
|
-
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
586
|
-
|
|
587
|
-
type Process = {
|
|
588
|
-
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
class UserService {
|
|
592
|
-
private _args: DtoUser | null
|
|
593
|
-
|
|
594
|
-
constructor(args: DtoUser | null = null) {
|
|
595
|
-
this._args = args
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
public process({ type }: Process): Promise<string | IUser[] | IUser> {
|
|
599
|
-
switch (type) {
|
|
600
|
-
case 'store':
|
|
601
|
-
return this._store()
|
|
602
|
-
case 'getAll':
|
|
603
|
-
return this._getAll()
|
|
604
|
-
case 'deleteAll':
|
|
605
|
-
return this._deleteAll()
|
|
606
|
-
case 'getOne':
|
|
607
|
-
return this._getOne()
|
|
608
|
-
case 'update':
|
|
609
|
-
return this._update()
|
|
610
|
-
case 'delete':
|
|
611
|
-
return this._delete()
|
|
612
|
-
default:
|
|
613
|
-
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
private async _store(): Promise<IUser> {
|
|
618
|
-
try {
|
|
619
|
-
const result = await store(this._args as DtoUser)
|
|
620
|
-
|
|
621
|
-
return result
|
|
622
|
-
} catch (e) {
|
|
623
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
private async _getAll(): Promise<IUser[]> {
|
|
628
|
-
try {
|
|
629
|
-
const users = (await get()) as IUser[]
|
|
630
|
-
|
|
631
|
-
return users
|
|
632
|
-
} catch (e) {
|
|
633
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
private async _deleteAll(): Promise<string> {
|
|
638
|
-
try {
|
|
639
|
-
const usersDeleted = (await remove()) as number
|
|
640
|
-
|
|
641
|
-
if (usersDeleted >= 1) return MFU.ALL_USERS_DELETED
|
|
642
|
-
|
|
643
|
-
if (usersDeleted === 0)
|
|
644
|
-
throw new httpErrors.Conflict(EFU.NOTHING_TO_DELETE)
|
|
753
|
+
const us = new UserService()
|
|
645
754
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
755
|
+
try {
|
|
756
|
+
const result = await us.process({ type: 'deleteAll' })
|
|
757
|
+
response({ error: false, message: result, res, status: 200 })
|
|
758
|
+
} catch (e) {
|
|
759
|
+
next(e)
|
|
760
|
+
}
|
|
649
761
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
private async _getOne(): Promise<IUser> {
|
|
653
|
-
const { id } = this._args as DtoUser
|
|
762
|
+
)
|
|
654
763
|
|
|
655
|
-
|
|
656
|
-
|
|
764
|
+
User.route('/user/:id')
|
|
765
|
+
.get(
|
|
766
|
+
async (
|
|
767
|
+
req: CustomRequest,
|
|
768
|
+
res: CustomResponse,
|
|
769
|
+
next: NextFunction
|
|
770
|
+
): Promise<void> => {
|
|
771
|
+
const {
|
|
772
|
+
params: { id }
|
|
773
|
+
} = req
|
|
657
774
|
|
|
658
|
-
|
|
775
|
+
try {
|
|
776
|
+
await idSchema.validateAsync(id)
|
|
777
|
+
const us = new UserService({ id })
|
|
778
|
+
const result = await us.process({ type: 'getOne' })
|
|
779
|
+
response({ error: false, message: result, res, status: 200 })
|
|
780
|
+
} catch (e) {
|
|
781
|
+
if (e instanceof ValidationError)
|
|
782
|
+
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
659
783
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
784
|
+
next(e)
|
|
785
|
+
}
|
|
663
786
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
787
|
+
)
|
|
788
|
+
.patch(
|
|
789
|
+
async (
|
|
790
|
+
req: CustomRequest,
|
|
791
|
+
res: CustomResponse,
|
|
792
|
+
next: NextFunction
|
|
793
|
+
): Promise<void> => {
|
|
794
|
+
const {
|
|
795
|
+
body: { args },
|
|
796
|
+
params: { id }
|
|
797
|
+
} = req
|
|
798
|
+
const user = {
|
|
799
|
+
id,
|
|
800
|
+
...args
|
|
801
|
+
}
|
|
669
802
|
|
|
670
|
-
|
|
803
|
+
try {
|
|
804
|
+
await userSchema.validateAsync(user)
|
|
805
|
+
const us = new UserService(user)
|
|
806
|
+
const result = await us.process({ type: 'update' })
|
|
807
|
+
response({ error: false, message: result, res, status: 200 })
|
|
808
|
+
} catch (e) {
|
|
809
|
+
if (e instanceof ValidationError)
|
|
810
|
+
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
671
811
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
812
|
+
next(e)
|
|
813
|
+
}
|
|
675
814
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
815
|
+
)
|
|
816
|
+
.delete(
|
|
817
|
+
async (
|
|
818
|
+
req: CustomRequest,
|
|
819
|
+
res: CustomResponse,
|
|
820
|
+
next: NextFunction
|
|
821
|
+
): Promise<void> => {
|
|
822
|
+
const {
|
|
823
|
+
params: { id }
|
|
824
|
+
} = req
|
|
683
825
|
|
|
684
|
-
|
|
826
|
+
try {
|
|
827
|
+
await idSchema.validateAsync(id)
|
|
828
|
+
const us = new UserService({ id })
|
|
829
|
+
const result = await us.process({ type: 'delete' })
|
|
830
|
+
response({ error: false, message: result, res, status: 200 })
|
|
831
|
+
} catch (e) {
|
|
832
|
+
if (e instanceof ValidationError)
|
|
833
|
+
return next(new httpErrors.UnprocessableEntity(e.message))
|
|
685
834
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
835
|
+
next(e)
|
|
836
|
+
}
|
|
689
837
|
}
|
|
690
|
-
|
|
691
|
-
}
|
|
838
|
+
)
|
|
692
839
|
|
|
693
|
-
export {
|
|
840
|
+
export { User }
|
|
694
841
|
`,
|
|
695
|
-
file: `${projectName}/src/
|
|
842
|
+
file: `${projectName}/src/network/routes/user.ts`
|
|
696
843
|
}
|
|
697
844
|
},
|
|
698
|
-
'
|
|
845
|
+
'network/routes/schemas': {
|
|
699
846
|
index: {
|
|
700
|
-
content: `import
|
|
701
|
-
|
|
702
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
703
|
-
const errorHandling = (e: any, message?: string): never => {
|
|
704
|
-
console.error(e)
|
|
705
|
-
|
|
706
|
-
if (e instanceof httpErrors.HttpError) throw e
|
|
707
|
-
|
|
708
|
-
throw new httpErrors.InternalServerError(message ?? e.message)
|
|
709
|
-
}
|
|
847
|
+
content: `import Joi from 'joi'
|
|
710
848
|
|
|
711
|
-
|
|
712
|
-
export * from './messages'
|
|
713
|
-
`,
|
|
714
|
-
file: `${projectName}/src/services/utils/index.ts`
|
|
715
|
-
}
|
|
716
|
-
},
|
|
717
|
-
'services/utils/messages': {
|
|
718
|
-
index: {
|
|
719
|
-
content: `enum GenericErrors {
|
|
720
|
-
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
721
|
-
}
|
|
849
|
+
const idSchema = Joi.string().length(24).required()
|
|
722
850
|
|
|
723
|
-
export {
|
|
851
|
+
export { idSchema }
|
|
724
852
|
export * from './user'
|
|
725
853
|
`,
|
|
726
|
-
file: `${projectName}/src/
|
|
854
|
+
file: `${projectName}/src/network/routes/schemas/index.ts`
|
|
727
855
|
},
|
|
728
856
|
user: {
|
|
729
|
-
content: `
|
|
730
|
-
NOT_FOUND = 'The requested user does not exists',
|
|
731
|
-
NOTHING_TO_DELETE = 'There is no user to be deleted'
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
enum MessageForUser {
|
|
735
|
-
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
736
|
-
USER_DELETED = 'The requested user was successfully deleted'
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
740
|
-
`,
|
|
741
|
-
file: `${projectName}/src/services/utils/messages/user.ts`
|
|
742
|
-
}
|
|
743
|
-
},
|
|
744
|
-
test: {
|
|
745
|
-
index: {
|
|
746
|
-
content: `### Testing store a user
|
|
747
|
-
POST http://localhost:1996/api/users
|
|
748
|
-
Content-Type: application/json
|
|
749
|
-
|
|
750
|
-
{
|
|
751
|
-
"args": {
|
|
752
|
-
"lastName": "Lzq",
|
|
753
|
-
"name": "Anthony"
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
### Testing getAll users
|
|
758
|
-
GET http://localhost:1996/api/users
|
|
759
|
-
|
|
760
|
-
### Testing deleteAll users
|
|
761
|
-
DELETE http://localhost:1996/api/users
|
|
762
|
-
|
|
763
|
-
### Testing getOne user
|
|
764
|
-
GET http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
857
|
+
content: `import Joi from 'joi'
|
|
765
858
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
859
|
+
const userSchema = Joi.object().keys({
|
|
860
|
+
id: Joi.string().length(24).required(),
|
|
861
|
+
lastName: Joi.string().required(),
|
|
862
|
+
name: Joi.string().required()
|
|
863
|
+
})
|
|
769
864
|
|
|
770
|
-
{
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
}
|
|
775
|
-
}
|
|
865
|
+
const storeUserSchema = Joi.object().keys({
|
|
866
|
+
lastName: Joi.string().required(),
|
|
867
|
+
name: Joi.string().required()
|
|
868
|
+
})
|
|
776
869
|
|
|
777
|
-
|
|
778
|
-
DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
870
|
+
export { userSchema, storeUserSchema }
|
|
779
871
|
`,
|
|
780
|
-
file: `${projectName}/
|
|
872
|
+
file: `${projectName}/src/network/routes/schemas/user.ts`
|
|
781
873
|
}
|
|
782
874
|
},
|
|
783
875
|
utils: {
|
|
@@ -933,8 +1025,70 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
933
1025
|
"tags": [
|
|
934
1026
|
"user"
|
|
935
1027
|
],
|
|
936
|
-
"summary": "Get an specific user",
|
|
937
|
-
"operationId": "getOne",
|
|
1028
|
+
"summary": "Get an specific user",
|
|
1029
|
+
"operationId": "getOne",
|
|
1030
|
+
"parameters": [
|
|
1031
|
+
{
|
|
1032
|
+
"name": "id",
|
|
1033
|
+
"in": "path",
|
|
1034
|
+
"description": "MongoDB user id",
|
|
1035
|
+
"required": true,
|
|
1036
|
+
"style": "simple",
|
|
1037
|
+
"explode": false,
|
|
1038
|
+
"schema": {
|
|
1039
|
+
"type": "string"
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
],
|
|
1043
|
+
"responses": {
|
|
1044
|
+
"200": {
|
|
1045
|
+
"description": "User stored in the database",
|
|
1046
|
+
"content": {
|
|
1047
|
+
"application/json": {
|
|
1048
|
+
"schema": {
|
|
1049
|
+
"$ref": "#/components/schemas/User"
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
"404": {
|
|
1055
|
+
"description": "User not found",
|
|
1056
|
+
"content": {
|
|
1057
|
+
"application/json": {
|
|
1058
|
+
"schema": {
|
|
1059
|
+
"$ref": "#/components/schemas/DefaultError"
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
"422": {
|
|
1065
|
+
"description": "Invalid request format",
|
|
1066
|
+
"content": {
|
|
1067
|
+
"application/json": {
|
|
1068
|
+
"schema": {
|
|
1069
|
+
"$ref": "#/components/schemas/DefaultError"
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
"500": {
|
|
1075
|
+
"description": "Internal server error",
|
|
1076
|
+
"content": {
|
|
1077
|
+
"application/json": {
|
|
1078
|
+
"schema": {
|
|
1079
|
+
"$ref": "#/components/schemas/DefaultError"
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
"patch": {
|
|
1087
|
+
"tags": [
|
|
1088
|
+
"user"
|
|
1089
|
+
],
|
|
1090
|
+
"summary": "Update the user data",
|
|
1091
|
+
"operationId": "update",
|
|
938
1092
|
"parameters": [
|
|
939
1093
|
{
|
|
940
1094
|
"name": "id",
|
|
@@ -948,9 +1102,12 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
948
1102
|
}
|
|
949
1103
|
}
|
|
950
1104
|
],
|
|
1105
|
+
"requestBody": {
|
|
1106
|
+
"$ref": "#/components/requestBodies/DtoUser"
|
|
1107
|
+
},
|
|
951
1108
|
"responses": {
|
|
952
1109
|
"200": {
|
|
953
|
-
"description": "User
|
|
1110
|
+
"description": "User successfully updated",
|
|
954
1111
|
"content": {
|
|
955
1112
|
"application/json": {
|
|
956
1113
|
"schema": {
|
|
@@ -991,12 +1148,12 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
991
1148
|
}
|
|
992
1149
|
}
|
|
993
1150
|
},
|
|
994
|
-
"
|
|
1151
|
+
"delete": {
|
|
995
1152
|
"tags": [
|
|
996
1153
|
"user"
|
|
997
1154
|
],
|
|
998
|
-
"summary": "
|
|
999
|
-
"operationId": "
|
|
1155
|
+
"summary": "Delete one user from the database",
|
|
1156
|
+
"operationId": "delete",
|
|
1000
1157
|
"parameters": [
|
|
1001
1158
|
{
|
|
1002
1159
|
"name": "id",
|
|
@@ -1010,16 +1167,13 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
1010
1167
|
}
|
|
1011
1168
|
}
|
|
1012
1169
|
],
|
|
1013
|
-
"requestBody": {
|
|
1014
|
-
"$ref": "#/components/requestBodies/DtoUser"
|
|
1015
|
-
},
|
|
1016
1170
|
"responses": {
|
|
1017
1171
|
"200": {
|
|
1018
|
-
"description": "User successfully
|
|
1172
|
+
"description": "User successfully deleted",
|
|
1019
1173
|
"content": {
|
|
1020
1174
|
"application/json": {
|
|
1021
1175
|
"schema": {
|
|
1022
|
-
"$ref": "#/components/schemas/
|
|
1176
|
+
"$ref": "#/components/schemas/DefaultSuccess"
|
|
1023
1177
|
}
|
|
1024
1178
|
}
|
|
1025
1179
|
}
|
|
@@ -1034,199 +1188,583 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
1034
1188
|
}
|
|
1035
1189
|
}
|
|
1036
1190
|
},
|
|
1037
|
-
"422": {
|
|
1038
|
-
"description": "Invalid request format",
|
|
1039
|
-
"content": {
|
|
1040
|
-
"application/json": {
|
|
1041
|
-
"schema": {
|
|
1042
|
-
"$ref": "#/components/schemas/DefaultError"
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1191
|
+
"422": {
|
|
1192
|
+
"description": "Invalid request format",
|
|
1193
|
+
"content": {
|
|
1194
|
+
"application/json": {
|
|
1195
|
+
"schema": {
|
|
1196
|
+
"$ref": "#/components/schemas/DefaultError"
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
},
|
|
1201
|
+
"500": {
|
|
1202
|
+
"description": "Internal server error",
|
|
1203
|
+
"content": {
|
|
1204
|
+
"application/json": {
|
|
1205
|
+
"schema": {
|
|
1206
|
+
"$ref": "#/components/schemas/DefaultError"
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
},
|
|
1215
|
+
"components": {
|
|
1216
|
+
"schemas": {
|
|
1217
|
+
"User": {
|
|
1218
|
+
"type": "object",
|
|
1219
|
+
"properties": {
|
|
1220
|
+
"id": {
|
|
1221
|
+
"type": "string"
|
|
1222
|
+
},
|
|
1223
|
+
"lastName": {
|
|
1224
|
+
"type": "string"
|
|
1225
|
+
},
|
|
1226
|
+
"name": {
|
|
1227
|
+
"type": "string"
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
"DefaultSuccess": {
|
|
1232
|
+
"type": "object",
|
|
1233
|
+
"properties": {
|
|
1234
|
+
"error": {
|
|
1235
|
+
"type": "boolean",
|
|
1236
|
+
"default": false
|
|
1237
|
+
},
|
|
1238
|
+
"message": {
|
|
1239
|
+
"type": "object",
|
|
1240
|
+
"properties": {
|
|
1241
|
+
"result": {
|
|
1242
|
+
"type": "string"
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
},
|
|
1248
|
+
"DefaultError": {
|
|
1249
|
+
"type": "object",
|
|
1250
|
+
"properties": {
|
|
1251
|
+
"error": {
|
|
1252
|
+
"type": "boolean",
|
|
1253
|
+
"default": true
|
|
1254
|
+
},
|
|
1255
|
+
"message": {
|
|
1256
|
+
"type": "object",
|
|
1257
|
+
"properties": {
|
|
1258
|
+
"result": {
|
|
1259
|
+
"type": "string"
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
"requestBodies": {
|
|
1267
|
+
"DtoUser": {
|
|
1268
|
+
"description": "User name and last name",
|
|
1269
|
+
"content": {
|
|
1270
|
+
"application/json": {
|
|
1271
|
+
"schema": {
|
|
1272
|
+
"type": "object",
|
|
1273
|
+
"properties": {
|
|
1274
|
+
"args": {
|
|
1275
|
+
"type": "object",
|
|
1276
|
+
"properties": {
|
|
1277
|
+
"name": {
|
|
1278
|
+
"type": "string"
|
|
1279
|
+
},
|
|
1280
|
+
"lastName": {
|
|
1281
|
+
"type": "string"
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
"required": true
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}`,
|
|
1294
|
+
file: `${projectName}/src/utils/docs.json`
|
|
1295
|
+
},
|
|
1296
|
+
index: {
|
|
1297
|
+
content: "export { default as docs } from './docs.json'\n",
|
|
1298
|
+
file: `${projectName}/src/utils/index.ts`
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
const fastifyData = {
|
|
1304
|
+
network: {
|
|
1305
|
+
response: {
|
|
1306
|
+
content: `import { FastifyReply } from 'fastify'
|
|
1307
|
+
|
|
1308
|
+
const response = ({
|
|
1309
|
+
error,
|
|
1310
|
+
message,
|
|
1311
|
+
reply,
|
|
1312
|
+
status
|
|
1313
|
+
}: {
|
|
1314
|
+
error: boolean
|
|
1315
|
+
message: unknown
|
|
1316
|
+
reply: FastifyReply
|
|
1317
|
+
status: number
|
|
1318
|
+
}): void => {
|
|
1319
|
+
reply.code(status).send({ error, message })
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
export { response }
|
|
1323
|
+
`,
|
|
1324
|
+
file: `${projectName}/src/network/response.ts`
|
|
1325
|
+
},
|
|
1326
|
+
router: {
|
|
1327
|
+
content: `import { FastifyInstance } from 'fastify'
|
|
1328
|
+
import { HttpError } from 'http-errors'
|
|
1329
|
+
|
|
1330
|
+
import { response } from './response'
|
|
1331
|
+
import { Home, User, Docs } from './routes'
|
|
1332
|
+
|
|
1333
|
+
const routers = [Docs, User]
|
|
1334
|
+
|
|
1335
|
+
const applyRoutes = (app: FastifyInstance): void => {
|
|
1336
|
+
Home(app)
|
|
1337
|
+
routers.forEach(router => router(app))
|
|
1338
|
+
|
|
1339
|
+
// Handling 404 error
|
|
1340
|
+
app.setNotFoundHandler((request, reply) => {
|
|
1341
|
+
response({
|
|
1342
|
+
error: true,
|
|
1343
|
+
message: 'This route does not exists',
|
|
1344
|
+
reply,
|
|
1345
|
+
status: 404
|
|
1346
|
+
})
|
|
1347
|
+
})
|
|
1348
|
+
app.setErrorHandler<HttpError>((error, request, reply) => {
|
|
1349
|
+
response({
|
|
1350
|
+
error: true,
|
|
1351
|
+
message: error.message,
|
|
1352
|
+
reply,
|
|
1353
|
+
status: error.status ?? 500
|
|
1354
|
+
})
|
|
1355
|
+
})
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
export { applyRoutes }
|
|
1359
|
+
`,
|
|
1360
|
+
file: `${projectName}/src/network/router.ts`
|
|
1361
|
+
},
|
|
1362
|
+
server: {
|
|
1363
|
+
content: `import Fastify, { FastifyInstance } from 'fastify'
|
|
1364
|
+
import mongoose from 'mongoose'
|
|
1365
|
+
|
|
1366
|
+
import { applyRoutes } from './router'
|
|
1367
|
+
|
|
1368
|
+
const PORT = process.env.PORT ?? '1996'
|
|
1369
|
+
|
|
1370
|
+
class Server {
|
|
1371
|
+
private _app: FastifyInstance
|
|
1372
|
+
private _connection: mongoose.Connection | undefined
|
|
1373
|
+
|
|
1374
|
+
constructor() {
|
|
1375
|
+
this._app = Fastify({ logger: true })
|
|
1376
|
+
this._config()
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
private _config() {
|
|
1380
|
+
this._app.addHook('preHandler', (req, reply, done) => {
|
|
1381
|
+
reply.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
|
|
1382
|
+
reply.header('Access-Control-Allow-Origin', '*')
|
|
1383
|
+
reply.header(
|
|
1384
|
+
'Access-Control-Allow-Headers',
|
|
1385
|
+
'Authorization, Content-Type'
|
|
1386
|
+
)
|
|
1387
|
+
done()
|
|
1388
|
+
})
|
|
1389
|
+
applyRoutes(this._app)
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
private async _mongo(): Promise<void> {
|
|
1393
|
+
this._connection = mongoose.connection
|
|
1394
|
+
const connection = {
|
|
1395
|
+
keepAlive: true,
|
|
1396
|
+
useNewUrlParser: true,
|
|
1397
|
+
useUnifiedTopology: true
|
|
1398
|
+
}
|
|
1399
|
+
this._connection.on('connected', () => {
|
|
1400
|
+
this._app.log.info('Mongo connection established.')
|
|
1401
|
+
})
|
|
1402
|
+
this._connection.on('reconnected', () => {
|
|
1403
|
+
this._app.log.info('Mongo connection reestablished')
|
|
1404
|
+
})
|
|
1405
|
+
this._connection.on('disconnected', () => {
|
|
1406
|
+
this._app.log.info('Mongo connection disconnected')
|
|
1407
|
+
this._app.log.info('Trying to reconnected to Mongo...')
|
|
1408
|
+
setTimeout(() => {
|
|
1409
|
+
mongoose.connect(process.env.MONGO_URI as string, {
|
|
1410
|
+
...connection,
|
|
1411
|
+
connectTimeoutMS: 3000,
|
|
1412
|
+
socketTimeoutMS: 3000
|
|
1413
|
+
})
|
|
1414
|
+
}, 3000)
|
|
1415
|
+
})
|
|
1416
|
+
this._connection.on('close', () => {
|
|
1417
|
+
this._app.log.info('Mongo connection closed')
|
|
1418
|
+
})
|
|
1419
|
+
this._connection.on('error', (e: Error) => {
|
|
1420
|
+
this._app.log.info('Mongo connection error:')
|
|
1421
|
+
this._app.log.error(e)
|
|
1422
|
+
})
|
|
1423
|
+
await mongoose.connect(process.env.MONGO_URI as string, connection)
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
public async start(): Promise<void> {
|
|
1427
|
+
try {
|
|
1428
|
+
await this._app.listen(PORT)
|
|
1429
|
+
this._mongo()
|
|
1430
|
+
} catch (e) {
|
|
1431
|
+
console.error(e)
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const server = new Server()
|
|
1437
|
+
|
|
1438
|
+
export { server as Server }
|
|
1439
|
+
`,
|
|
1440
|
+
file: `${projectName}/src/network/server.ts`
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
'network/routes': {
|
|
1444
|
+
docs: {
|
|
1445
|
+
content: `import { FastifyInstance } from 'fastify'
|
|
1446
|
+
import fastifySwagger from 'fastify-swagger'
|
|
1447
|
+
|
|
1448
|
+
const Docs = (app: FastifyInstance, prefix = '/api'): void => {
|
|
1449
|
+
app.register(fastifySwagger, {
|
|
1450
|
+
routePrefix: \`\${prefix}/docs\`,
|
|
1451
|
+
openapi: {
|
|
1452
|
+
info: {
|
|
1453
|
+
title: 'Test swagger',
|
|
1454
|
+
description: 'Testing the Fastify swagger API',
|
|
1455
|
+
version: '0.1.0',
|
|
1456
|
+
contact: {
|
|
1457
|
+
email: 'sluzquinosa@uni.pe'
|
|
1458
|
+
},
|
|
1459
|
+
license: {
|
|
1460
|
+
name: 'MIT',
|
|
1461
|
+
url: 'https://opensource.org/licenses/MIT'
|
|
1462
|
+
}
|
|
1463
|
+
},
|
|
1464
|
+
servers: [
|
|
1465
|
+
{
|
|
1466
|
+
url: 'http://localhost:1996/api',
|
|
1467
|
+
description: 'test-fastify local API'
|
|
1468
|
+
}
|
|
1469
|
+
],
|
|
1470
|
+
tags: [
|
|
1471
|
+
{
|
|
1472
|
+
name: 'user',
|
|
1473
|
+
description: 'User related endpoints'
|
|
1474
|
+
}
|
|
1475
|
+
]
|
|
1476
|
+
},
|
|
1477
|
+
exposeRoute: true
|
|
1478
|
+
})
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
export { Docs }
|
|
1482
|
+
`,
|
|
1483
|
+
file: `${projectName}/src/network/routes/docs.ts`
|
|
1484
|
+
},
|
|
1485
|
+
home: {
|
|
1486
|
+
content: `import { FastifyInstance } from 'fastify'
|
|
1487
|
+
import { response } from 'network/response'
|
|
1488
|
+
|
|
1489
|
+
const Home = (app: FastifyInstance, prefix = '/'): void => {
|
|
1490
|
+
app.get(\`\${prefix}\`, (request, reply) => {
|
|
1491
|
+
response({
|
|
1492
|
+
error: false,
|
|
1493
|
+
message: 'Welcome to your Fastify Backend!',
|
|
1494
|
+
reply,
|
|
1495
|
+
status: 200
|
|
1496
|
+
})
|
|
1497
|
+
})
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
export { Home }
|
|
1501
|
+
`,
|
|
1502
|
+
file: `${projectName}/src/network/routes/home.ts`
|
|
1503
|
+
},
|
|
1504
|
+
index: {
|
|
1505
|
+
content: `export * from './home'
|
|
1506
|
+
export * from './user'
|
|
1507
|
+
export * from './docs'
|
|
1508
|
+
`,
|
|
1509
|
+
file: `${projectName}/src/network/routes/index.ts`
|
|
1510
|
+
},
|
|
1511
|
+
user: {
|
|
1512
|
+
content: `import { FastifyInstance } from 'fastify'
|
|
1513
|
+
|
|
1514
|
+
import { response } from 'network/response'
|
|
1515
|
+
import { userSchema, idSchema, storeUserSchema } from './schemas'
|
|
1516
|
+
import { UserService } from 'services'
|
|
1517
|
+
|
|
1518
|
+
const User = (app: FastifyInstance, prefix = '/api'): void => {
|
|
1519
|
+
app
|
|
1520
|
+
.post<{ Body: { args: Omit<DtoUser, 'id'> } }>(
|
|
1521
|
+
\`\${prefix}/users\`,
|
|
1522
|
+
{
|
|
1523
|
+
schema: {
|
|
1524
|
+
body: {
|
|
1525
|
+
args: storeUserSchema
|
|
1526
|
+
},
|
|
1527
|
+
response: {
|
|
1528
|
+
200: {
|
|
1529
|
+
error: {
|
|
1530
|
+
type: 'boolean'
|
|
1531
|
+
},
|
|
1532
|
+
message: userSchema
|
|
1045
1533
|
}
|
|
1046
1534
|
},
|
|
1047
|
-
|
|
1048
|
-
"description": "Internal server error",
|
|
1049
|
-
"content": {
|
|
1050
|
-
"application/json": {
|
|
1051
|
-
"schema": {
|
|
1052
|
-
"$ref": "#/components/schemas/DefaultError"
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1535
|
+
tags: ['user']
|
|
1057
1536
|
}
|
|
1058
1537
|
},
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
"summary": "Delete one user from the database",
|
|
1064
|
-
"operationId": "delete",
|
|
1065
|
-
"parameters": [
|
|
1066
|
-
{
|
|
1067
|
-
"name": "id",
|
|
1068
|
-
"in": "path",
|
|
1069
|
-
"description": "MongoDB user id",
|
|
1070
|
-
"required": true,
|
|
1071
|
-
"style": "simple",
|
|
1072
|
-
"explode": false,
|
|
1073
|
-
"schema": {
|
|
1074
|
-
"type": "string"
|
|
1075
|
-
}
|
|
1538
|
+
async (request, reply) => {
|
|
1539
|
+
const {
|
|
1540
|
+
body: {
|
|
1541
|
+
args: { lastName, name }
|
|
1076
1542
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1543
|
+
} = request
|
|
1544
|
+
const us = new UserService({ lastName, name })
|
|
1545
|
+
const user = await us.process({ type: 'store' })
|
|
1546
|
+
|
|
1547
|
+
response({
|
|
1548
|
+
error: false,
|
|
1549
|
+
message: user,
|
|
1550
|
+
reply,
|
|
1551
|
+
status: 200
|
|
1552
|
+
})
|
|
1553
|
+
}
|
|
1554
|
+
)
|
|
1555
|
+
.get(
|
|
1556
|
+
\`\${prefix}/users\`,
|
|
1557
|
+
{
|
|
1558
|
+
schema: {
|
|
1559
|
+
response: {
|
|
1560
|
+
200: {
|
|
1561
|
+
error: {
|
|
1562
|
+
type: 'boolean'
|
|
1563
|
+
},
|
|
1564
|
+
message: {
|
|
1565
|
+
type: 'array',
|
|
1566
|
+
items: userSchema
|
|
1096
1567
|
}
|
|
1097
1568
|
}
|
|
1098
1569
|
},
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1570
|
+
tags: ['user']
|
|
1571
|
+
}
|
|
1572
|
+
},
|
|
1573
|
+
async (request, reply) => {
|
|
1574
|
+
const us = new UserService()
|
|
1575
|
+
const users = await us.process({ type: 'getAll' })
|
|
1576
|
+
|
|
1577
|
+
response({
|
|
1578
|
+
error: false,
|
|
1579
|
+
message: users,
|
|
1580
|
+
reply,
|
|
1581
|
+
status: 200
|
|
1582
|
+
})
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
.delete(
|
|
1586
|
+
\`\${prefix}/users\`,
|
|
1587
|
+
{
|
|
1588
|
+
schema: {
|
|
1589
|
+
response: {
|
|
1590
|
+
200: {
|
|
1591
|
+
error: {
|
|
1592
|
+
type: 'boolean'
|
|
1593
|
+
},
|
|
1594
|
+
message: {
|
|
1595
|
+
type: 'string'
|
|
1106
1596
|
}
|
|
1107
1597
|
}
|
|
1108
1598
|
},
|
|
1109
|
-
|
|
1110
|
-
"description": "Internal server error",
|
|
1111
|
-
"content": {
|
|
1112
|
-
"application/json": {
|
|
1113
|
-
"schema": {
|
|
1114
|
-
"$ref": "#/components/schemas/DefaultError"
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1599
|
+
tags: ['user']
|
|
1119
1600
|
}
|
|
1601
|
+
},
|
|
1602
|
+
async (request, reply) => {
|
|
1603
|
+
const us = new UserService()
|
|
1604
|
+
const result = await us.process({ type: 'deleteAll' })
|
|
1605
|
+
|
|
1606
|
+
response({
|
|
1607
|
+
error: false,
|
|
1608
|
+
message: result,
|
|
1609
|
+
reply,
|
|
1610
|
+
status: 200
|
|
1611
|
+
})
|
|
1120
1612
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
"id": {
|
|
1129
|
-
"type": "string"
|
|
1613
|
+
)
|
|
1614
|
+
.get<{ Params: { id: string } }>(
|
|
1615
|
+
\`\${prefix}/user/:id\`,
|
|
1616
|
+
{
|
|
1617
|
+
schema: {
|
|
1618
|
+
params: {
|
|
1619
|
+
id: idSchema
|
|
1130
1620
|
},
|
|
1131
|
-
|
|
1132
|
-
|
|
1621
|
+
response: {
|
|
1622
|
+
200: {
|
|
1623
|
+
error: {
|
|
1624
|
+
type: 'boolean'
|
|
1625
|
+
},
|
|
1626
|
+
message: userSchema
|
|
1627
|
+
}
|
|
1133
1628
|
},
|
|
1134
|
-
|
|
1135
|
-
"type": "string"
|
|
1136
|
-
}
|
|
1629
|
+
tags: ['user']
|
|
1137
1630
|
}
|
|
1138
1631
|
},
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1632
|
+
async (request, reply) => {
|
|
1633
|
+
const {
|
|
1634
|
+
params: { id }
|
|
1635
|
+
} = request
|
|
1636
|
+
const us = new UserService({ id })
|
|
1637
|
+
const user = await us.process({ type: 'getOne' })
|
|
1638
|
+
|
|
1639
|
+
response({
|
|
1640
|
+
error: false,
|
|
1641
|
+
message: user,
|
|
1642
|
+
reply,
|
|
1643
|
+
status: 200
|
|
1644
|
+
})
|
|
1645
|
+
}
|
|
1646
|
+
)
|
|
1647
|
+
.patch<{ Body: { args: Omit<DtoUser, 'id'> }; Params: { id: string } }>(
|
|
1648
|
+
\`\${prefix}/user/:id\`,
|
|
1649
|
+
{
|
|
1650
|
+
schema: {
|
|
1651
|
+
body: {
|
|
1652
|
+
args: userSchema
|
|
1145
1653
|
},
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1654
|
+
params: {
|
|
1655
|
+
id: idSchema
|
|
1656
|
+
},
|
|
1657
|
+
response: {
|
|
1658
|
+
200: {
|
|
1659
|
+
error: {
|
|
1660
|
+
type: 'boolean'
|
|
1661
|
+
},
|
|
1662
|
+
message: userSchema
|
|
1152
1663
|
}
|
|
1153
|
-
}
|
|
1664
|
+
},
|
|
1665
|
+
tags: ['user']
|
|
1154
1666
|
}
|
|
1155
1667
|
},
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
"type": "boolean",
|
|
1161
|
-
"default": true
|
|
1668
|
+
async (request, reply) => {
|
|
1669
|
+
const {
|
|
1670
|
+
body: {
|
|
1671
|
+
args: { name, lastName }
|
|
1162
1672
|
},
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1673
|
+
params: { id }
|
|
1674
|
+
} = request
|
|
1675
|
+
const us = new UserService({ name, lastName, id })
|
|
1676
|
+
const user = await us.process({ type: 'update' })
|
|
1677
|
+
|
|
1678
|
+
response({
|
|
1679
|
+
error: false,
|
|
1680
|
+
message: user,
|
|
1681
|
+
reply,
|
|
1682
|
+
status: 200
|
|
1683
|
+
})
|
|
1172
1684
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
"lastName": {
|
|
1189
|
-
"type": "string"
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1685
|
+
)
|
|
1686
|
+
.delete<{ Params: { id: string } }>(
|
|
1687
|
+
\`\${prefix}/user/:id\`,
|
|
1688
|
+
{
|
|
1689
|
+
schema: {
|
|
1690
|
+
params: {
|
|
1691
|
+
id: idSchema
|
|
1692
|
+
},
|
|
1693
|
+
response: {
|
|
1694
|
+
200: {
|
|
1695
|
+
error: {
|
|
1696
|
+
type: 'boolean'
|
|
1697
|
+
},
|
|
1698
|
+
message: {
|
|
1699
|
+
type: 'string'
|
|
1193
1700
|
}
|
|
1194
1701
|
}
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
}`,
|
|
1202
|
-
file: `${projectName}/src/utils/docs.json`
|
|
1702
|
+
},
|
|
1703
|
+
tags: ['user']
|
|
1704
|
+
}
|
|
1203
1705
|
},
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1706
|
+
async (request, reply) => {
|
|
1707
|
+
const {
|
|
1708
|
+
params: { id }
|
|
1709
|
+
} = request
|
|
1710
|
+
const us = new UserService({ id })
|
|
1711
|
+
const result = await us.process({ type: 'delete' })
|
|
1712
|
+
|
|
1713
|
+
response({
|
|
1714
|
+
error: false,
|
|
1715
|
+
message: result,
|
|
1716
|
+
reply,
|
|
1717
|
+
status: 200
|
|
1718
|
+
})
|
|
1719
|
+
}
|
|
1720
|
+
)
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
export { User }
|
|
1724
|
+
`,
|
|
1725
|
+
file: `${projectName}/src/network/routes/user.ts`
|
|
1207
1726
|
}
|
|
1208
1727
|
},
|
|
1209
|
-
'
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
},
|
|
1213
|
-
index: {
|
|
1214
|
-
content: `import { Server } from './network'
|
|
1728
|
+
'network/routes/schemas': {
|
|
1729
|
+
index: {
|
|
1730
|
+
content: `import { Type } from '@sinclair/typebox'
|
|
1215
1731
|
|
|
1216
|
-
|
|
1732
|
+
const idSchema = Type.String({ minLength: 24, maxLength: 24 })
|
|
1733
|
+
|
|
1734
|
+
export { idSchema }
|
|
1735
|
+
export * from './user'
|
|
1217
1736
|
`,
|
|
1218
|
-
|
|
1737
|
+
file: `${projectName}/src/network/routes/schemas/index.ts`
|
|
1738
|
+
},
|
|
1739
|
+
user: {
|
|
1740
|
+
content: `import { Type } from '@sinclair/typebox'
|
|
1741
|
+
|
|
1742
|
+
const userSchema = Type.Object({
|
|
1743
|
+
id: Type.Optional(Type.String({ minLength: 24, maxLength: 24 })),
|
|
1744
|
+
lastName: Type.Optional(Type.String()),
|
|
1745
|
+
name: Type.Optional(Type.String()),
|
|
1746
|
+
updatedAt: Type.Optional(Type.String())
|
|
1747
|
+
})
|
|
1748
|
+
|
|
1749
|
+
const storeUserSchema = Type.Object({
|
|
1750
|
+
lastName: Type.String(),
|
|
1751
|
+
name: Type.String()
|
|
1752
|
+
})
|
|
1753
|
+
|
|
1754
|
+
export { userSchema, storeUserSchema }
|
|
1755
|
+
`,
|
|
1756
|
+
file: `${projectName}/src/network/routes/schemas/user.ts`
|
|
1757
|
+
}
|
|
1219
1758
|
}
|
|
1220
1759
|
}
|
|
1221
1760
|
|
|
1761
|
+
const expressFolders = `${projectName}/src/utils`
|
|
1762
|
+
|
|
1222
1763
|
const createFoldersCommands = `mkdir ${projectName}/src \
|
|
1223
1764
|
${projectName}/src/@types \
|
|
1224
1765
|
${projectName}/src/@types/dto \
|
|
1225
1766
|
${projectName}/src/@types/custom \
|
|
1226
1767
|
${projectName}/src/@types/models \
|
|
1227
|
-
${projectName}/src/services \
|
|
1228
|
-
${projectName}/src/services/utils \
|
|
1229
|
-
${projectName}/src/services/utils/messages \
|
|
1230
1768
|
${projectName}/src/database \
|
|
1231
1769
|
${projectName}/src/database/mongo \
|
|
1232
1770
|
${projectName}/src/database/mongo/models \
|
|
@@ -1234,8 +1772,10 @@ ${projectName}/src/database/mongo/queries \
|
|
|
1234
1772
|
${projectName}/src/network \
|
|
1235
1773
|
${projectName}/src/network/routes \
|
|
1236
1774
|
${projectName}/src/network/routes/schemas \
|
|
1237
|
-
${projectName}/src/
|
|
1238
|
-
${projectName}/src/utils
|
|
1775
|
+
${projectName}/src/services \
|
|
1776
|
+
${projectName}/src/services/utils \
|
|
1777
|
+
${projectName}/src/services/utils/messages \
|
|
1778
|
+
${fastify ? '' : `${expressFolders}`}
|
|
1239
1779
|
`
|
|
1240
1780
|
|
|
1241
1781
|
if (os.platform() === 'win32')
|
|
@@ -1245,16 +1785,6 @@ ${projectName}/src/utils
|
|
|
1245
1785
|
// /@types
|
|
1246
1786
|
await writeFile(data['@types'].index.file, data['@types'].index.content)
|
|
1247
1787
|
|
|
1248
|
-
// /@types/custom
|
|
1249
|
-
await writeFile(
|
|
1250
|
-
data['@types/custom'].request.file,
|
|
1251
|
-
data['@types/custom'].request.content
|
|
1252
|
-
)
|
|
1253
|
-
await writeFile(
|
|
1254
|
-
data['@types/custom'].response.file,
|
|
1255
|
-
data['@types/custom'].response.content
|
|
1256
|
-
)
|
|
1257
|
-
|
|
1258
1788
|
// /@types/dto
|
|
1259
1789
|
await writeFile(data['@types/dto'].user.file, data['@types/dto'].user.content)
|
|
1260
1790
|
|
|
@@ -1309,44 +1839,112 @@ ${projectName}/src/utils
|
|
|
1309
1839
|
|
|
1310
1840
|
// /network
|
|
1311
1841
|
await writeFile(data.network.index.file, data.network.index.content)
|
|
1312
|
-
await writeFile(data.network.response.file, data.network.response.content)
|
|
1313
|
-
await writeFile(data.network.router.file, data.network.router.content)
|
|
1314
|
-
await writeFile(data.network.server.file, data.network.server.content)
|
|
1315
|
-
|
|
1316
|
-
// /network/routes
|
|
1317
|
-
await writeFile(
|
|
1318
|
-
data['network/routes'].home.file,
|
|
1319
|
-
data['network/routes'].home.content
|
|
1320
|
-
)
|
|
1321
|
-
await writeFile(
|
|
1322
|
-
data['network/routes'].user.file,
|
|
1323
|
-
data['network/routes'].user.content
|
|
1324
|
-
)
|
|
1325
|
-
await writeFile(
|
|
1326
|
-
data['network/routes'].index.file,
|
|
1327
|
-
data['network/routes'].index.content
|
|
1328
|
-
)
|
|
1329
|
-
|
|
1330
|
-
// /network/routes/schemas
|
|
1331
|
-
await writeFile(
|
|
1332
|
-
data['network/routes/schemas'].index.file,
|
|
1333
|
-
data['network/routes/schemas'].index.content
|
|
1334
|
-
)
|
|
1335
|
-
await writeFile(
|
|
1336
|
-
data['network/routes/schemas'].user.file,
|
|
1337
|
-
data['network/routes/schemas'].user.content
|
|
1338
|
-
)
|
|
1339
1842
|
|
|
1340
1843
|
// /test
|
|
1341
1844
|
await writeFile(data.test.index.file, data.test.index.content)
|
|
1342
1845
|
|
|
1343
|
-
// /utils
|
|
1344
|
-
await writeFile(data.utils.docs.file, data.utils.docs.content)
|
|
1345
|
-
await writeFile(data.utils.index.file, data.utils.index.content)
|
|
1346
|
-
|
|
1347
1846
|
// .env
|
|
1348
1847
|
await writeFile(data['.env'].file, data['.env'].content)
|
|
1349
1848
|
|
|
1350
1849
|
// index
|
|
1351
1850
|
await writeFile(data.index.file, data.index.content)
|
|
1851
|
+
|
|
1852
|
+
if (fastify) {
|
|
1853
|
+
// /network
|
|
1854
|
+
await writeFile(
|
|
1855
|
+
fastifyData.network.response.file,
|
|
1856
|
+
fastifyData.network.response.content
|
|
1857
|
+
)
|
|
1858
|
+
await writeFile(
|
|
1859
|
+
fastifyData.network.router.file,
|
|
1860
|
+
fastifyData.network.router.content
|
|
1861
|
+
)
|
|
1862
|
+
await writeFile(
|
|
1863
|
+
fastifyData.network.server.file,
|
|
1864
|
+
fastifyData.network.server.content
|
|
1865
|
+
)
|
|
1866
|
+
|
|
1867
|
+
// /network/routes
|
|
1868
|
+
await writeFile(
|
|
1869
|
+
fastifyData['network/routes'].docs.file,
|
|
1870
|
+
fastifyData['network/routes'].docs.content
|
|
1871
|
+
)
|
|
1872
|
+
await writeFile(
|
|
1873
|
+
fastifyData['network/routes'].home.file,
|
|
1874
|
+
fastifyData['network/routes'].home.content
|
|
1875
|
+
)
|
|
1876
|
+
await writeFile(
|
|
1877
|
+
fastifyData['network/routes'].user.file,
|
|
1878
|
+
fastifyData['network/routes'].user.content
|
|
1879
|
+
)
|
|
1880
|
+
await writeFile(
|
|
1881
|
+
fastifyData['network/routes'].index.file,
|
|
1882
|
+
fastifyData['network/routes'].index.content
|
|
1883
|
+
)
|
|
1884
|
+
|
|
1885
|
+
// /network/routes/schemas
|
|
1886
|
+
await writeFile(
|
|
1887
|
+
fastifyData['network/routes/schemas'].index.file,
|
|
1888
|
+
fastifyData['network/routes/schemas'].index.content
|
|
1889
|
+
)
|
|
1890
|
+
await writeFile(
|
|
1891
|
+
fastifyData['network/routes/schemas'].user.file,
|
|
1892
|
+
fastifyData['network/routes/schemas'].user.content
|
|
1893
|
+
)
|
|
1894
|
+
} else {
|
|
1895
|
+
// /network
|
|
1896
|
+
await writeFile(
|
|
1897
|
+
expressData.network.response.file,
|
|
1898
|
+
expressData.network.response.content
|
|
1899
|
+
)
|
|
1900
|
+
await writeFile(
|
|
1901
|
+
expressData.network.router.file,
|
|
1902
|
+
expressData.network.router.content
|
|
1903
|
+
)
|
|
1904
|
+
await writeFile(
|
|
1905
|
+
expressData.network.server.file,
|
|
1906
|
+
expressData.network.server.content
|
|
1907
|
+
)
|
|
1908
|
+
|
|
1909
|
+
// /network/routes
|
|
1910
|
+
await writeFile(
|
|
1911
|
+
expressData['network/routes'].home.file,
|
|
1912
|
+
expressData['network/routes'].home.content
|
|
1913
|
+
)
|
|
1914
|
+
await writeFile(
|
|
1915
|
+
expressData['network/routes'].user.file,
|
|
1916
|
+
expressData['network/routes'].user.content
|
|
1917
|
+
)
|
|
1918
|
+
await writeFile(
|
|
1919
|
+
expressData['network/routes'].index.file,
|
|
1920
|
+
expressData['network/routes'].index.content
|
|
1921
|
+
)
|
|
1922
|
+
|
|
1923
|
+
// /network/routes/schemas
|
|
1924
|
+
await writeFile(
|
|
1925
|
+
expressData['network/routes/schemas'].index.file,
|
|
1926
|
+
expressData['network/routes/schemas'].index.content
|
|
1927
|
+
)
|
|
1928
|
+
await writeFile(
|
|
1929
|
+
expressData['network/routes/schemas'].user.file,
|
|
1930
|
+
expressData['network/routes/schemas'].user.content
|
|
1931
|
+
)
|
|
1932
|
+
|
|
1933
|
+
// /utils
|
|
1934
|
+
await writeFile(expressData.utils.docs.file, expressData.utils.docs.content)
|
|
1935
|
+
await writeFile(
|
|
1936
|
+
expressData.utils.index.file,
|
|
1937
|
+
expressData.utils.index.content
|
|
1938
|
+
)
|
|
1939
|
+
|
|
1940
|
+
// /@types/custom
|
|
1941
|
+
await writeFile(
|
|
1942
|
+
expressData['@types/custom'].request.file,
|
|
1943
|
+
expressData['@types/custom'].request.content
|
|
1944
|
+
)
|
|
1945
|
+
await writeFile(
|
|
1946
|
+
expressData['@types/custom'].response.file,
|
|
1947
|
+
expressData['@types/custom'].response.content
|
|
1948
|
+
)
|
|
1949
|
+
}
|
|
1352
1950
|
}
|