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