@anthonylzq/simba.js 1.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.
@@ -0,0 +1,1225 @@
1
+ const util = require('util')
2
+ const exec = util.promisify(require('child_process').exec)
3
+ const writeFile = require('../utils/writeFile')
4
+
5
+ /*
6
+ * src
7
+ * |- @types:
8
+ * | |- global: content, file
9
+ * |- controllers:
10
+ * | |- utils:
11
+ * | | |- messages:
12
+ * | | | |- user: content, file
13
+ * | | | |- index: content, file
14
+ * | | |- index: content, file
15
+ * | |- user: content, file
16
+ * | |- index: content, file
17
+ * |- dto-interfaces:
18
+ * | |- user: content, file
19
+ * | |- index: content, file
20
+ * |- models:
21
+ * | |- user: content, file
22
+ * | |- index: content, file
23
+ * |- network:
24
+ * | |- server: content, file
25
+ * | |- routes: content, file
26
+ * | |- index: content, file
27
+ * |- routes:
28
+ * | |- home: content, file
29
+ * | |- user: content, file
30
+ * | |- index: content, file
31
+ * |- schemas:
32
+ * | |- user: content, file
33
+ * | |- index: content, file
34
+ * |- test:
35
+ * | |- index.http: content, file
36
+ * |- utils:
37
+ * | |- docs.json: content, file
38
+ * | |- response: content, file
39
+ * | |- index: content, file
40
+ * |- .env: content, file
41
+ * |- index: content, file
42
+ */
43
+
44
+ /**
45
+ * @param {String} projectName
46
+ * @param {String} projectVersion
47
+ * @param {String} email
48
+ */
49
+ module.exports = async (projectName, projectVersion, email) => {
50
+ const data = {
51
+ '@types': {
52
+ index: {
53
+ content: `/* eslint-disable no-var */
54
+ import { IncomingHttpHeaders } from 'http'
55
+ import { Request, Response } from 'express'
56
+
57
+ import { DtoUser } from '../dto-interfaces'
58
+
59
+ declare global {
60
+ // This variable is global, so it will be available everywhere in the code
61
+ var myGlobalVariable: unknown
62
+
63
+ // We can personalize the response and request objects in case we need it by
64
+ // adding new optional attributes to this interface
65
+ interface CustomResponse extends Response {
66
+ newValue?: string
67
+ }
68
+
69
+ interface CustomRequest extends Request {
70
+ body: {
71
+ args?: DtoUser
72
+ }
73
+ // We can add custom headers via intersection, remember that for some reason
74
+ // headers must be in Snake-Pascal-Case
75
+ headers: IncomingHttpHeaders & {
76
+ 'Custom-Header'?: string
77
+ }
78
+ }
79
+ }
80
+
81
+ export {}
82
+ `,
83
+ file: `${projectName}/src/@types/index.d.ts`
84
+ }
85
+ },
86
+ controllers: {
87
+ index: {
88
+ content: `import { User } from './user'
89
+
90
+ export { User }
91
+ `,
92
+ file: `${projectName}/src/controllers/index.ts`
93
+ },
94
+ user: {
95
+ content: `import httpErrors from 'http-errors'
96
+
97
+ import { DtoUser } from '../dto-interfaces'
98
+ import { IUser, UserModel } from '../models'
99
+ import { EFU, MFU, GE, errorHandling } from './utils'
100
+
101
+ type Process = {
102
+ type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
103
+ }
104
+
105
+ class User {
106
+ private _args: DtoUser | null
107
+
108
+ constructor(args: DtoUser | null = null) {
109
+ this._args = args
110
+ }
111
+
112
+ public process({
113
+ type
114
+ }: Process): Promise<string> | Promise<IUser[]> | Promise<IUser> {
115
+ switch (type) {
116
+ case 'store':
117
+ return this._store()
118
+ case 'getAll':
119
+ return this._getAll()
120
+ case 'deleteAll':
121
+ return this._deleteAll()
122
+ case 'getOne':
123
+ return this._getOne()
124
+ case 'update':
125
+ return this._update()
126
+ case 'delete':
127
+ return this._delete()
128
+ default:
129
+ throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
130
+ }
131
+ }
132
+
133
+ private async _store(): Promise<IUser> {
134
+ const { lastName, name } = this._args as DtoUser
135
+
136
+ try {
137
+ const newUser = new UserModel({ lastName, name })
138
+ const result = await newUser.save()
139
+
140
+ return result
141
+ } catch (e) {
142
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
143
+ }
144
+ }
145
+
146
+ private async _getAll(): Promise<IUser[]> {
147
+ try {
148
+ const users = await UserModel.find({})
149
+
150
+ return users
151
+ } catch (e) {
152
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
153
+ }
154
+ }
155
+
156
+ private async _deleteAll(): Promise<string> {
157
+ try {
158
+ const usersDeleted = await UserModel.deleteMany({})
159
+
160
+ if (usersDeleted.acknowledged) return MFU.ALL_USERS_DELETED
161
+
162
+ throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
163
+ } catch (e) {
164
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
165
+ }
166
+ }
167
+
168
+ private async _getOne(): Promise<IUser> {
169
+ const { id } = this._args as DtoUser
170
+
171
+ try {
172
+ const user = await UserModel.findById(id)
173
+
174
+ if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
175
+
176
+ return user
177
+ } catch (e) {
178
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
179
+ }
180
+ }
181
+
182
+ private async _update(): Promise<IUser> {
183
+ const { id, lastName, name } = this._args as DtoUser
184
+
185
+ try {
186
+ const updatedUser = await UserModel.findByIdAndUpdate(
187
+ id,
188
+ { lastName, name },
189
+ { new: true }
190
+ )
191
+
192
+ if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
193
+
194
+ return updatedUser
195
+ } catch (e) {
196
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
197
+ }
198
+ }
199
+
200
+ private async _delete(): Promise<string> {
201
+ const { id } = this._args as DtoUser
202
+
203
+ try {
204
+ const deletedUser = await UserModel.findByIdAndRemove(id)
205
+
206
+ if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
207
+
208
+ return MFU.USER_DELETED
209
+ } catch (e) {
210
+ return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
211
+ }
212
+ }
213
+ }
214
+
215
+ export { User }
216
+ `,
217
+ file: `${projectName}/src/controllers/user.ts`
218
+ }
219
+ },
220
+ 'controllers/utils': {
221
+ index: {
222
+ content: `import httpErrors from 'http-errors'
223
+
224
+ import { EFU, MFU, GE } from './messages'
225
+
226
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
227
+ const errorHandling = (e: any, message?: string): never => {
228
+ console.error(e)
229
+
230
+ if (e instanceof httpErrors.HttpError) throw e
231
+
232
+ throw new httpErrors.InternalServerError(message ?? e.message)
233
+ }
234
+
235
+ export { EFU, MFU, GE, errorHandling }
236
+ `,
237
+ file: `${projectName}/src/controllers/utils/index.ts`
238
+ }
239
+ },
240
+ 'controllers/utils/messages': {
241
+ index: {
242
+ content: `import { EFU, MFU } from './user'
243
+
244
+ enum GenericErrors {
245
+ INTERNAL_SERVER_ERROR = 'Something went wrong'
246
+ }
247
+
248
+ export { EFU, MFU, GenericErrors as GE }
249
+ `,
250
+ file: `${projectName}/src/controllers/utils/messages/index.ts`
251
+ },
252
+ user: {
253
+ content: `enum ErrorForUser {
254
+ NOT_FOUND = 'The requested user does not exists'
255
+ }
256
+
257
+ enum MessageForUser {
258
+ ALL_USERS_DELETED = 'All the users were deleted successfully',
259
+ USER_DELETED = 'The requested user was successfully deleted'
260
+ }
261
+
262
+ export { ErrorForUser as EFU, MessageForUser as MFU }
263
+ `,
264
+ file: `${projectName}/src/controllers/utils/messages/user.ts`
265
+ }
266
+ },
267
+ 'dto-interfaces': {
268
+ index: {
269
+ content: `import { DtoUser } from './user'
270
+
271
+ export { DtoUser }
272
+ `,
273
+ file: `${projectName}/src/dto-interfaces/index.ts`
274
+ },
275
+ user: {
276
+ content: `interface DtoUser {
277
+ id: string
278
+ lastName?: string
279
+ name?: string
280
+ }
281
+
282
+ export { DtoUser }
283
+ `,
284
+ file: `${projectName}/src/dto-interfaces/user.ts`
285
+ }
286
+ },
287
+ models: {
288
+ index: {
289
+ content: `import { IUser, UserModel } from './user'
290
+
291
+ export { IUser, UserModel }
292
+ `,
293
+ file: `${projectName}/src/models/index.ts`
294
+ },
295
+ user: {
296
+ content: `/* eslint-disable no-underscore-dangle */
297
+ import { Document, model, Schema } from 'mongoose'
298
+
299
+ interface IUser extends Document {
300
+ lastName: string
301
+ name: string
302
+ updatedAt: Date
303
+ }
304
+
305
+ const User = new Schema(
306
+ {
307
+ lastName: {
308
+ required: true,
309
+ type: String
310
+ },
311
+ name: {
312
+ required: true,
313
+ type: String
314
+ }
315
+ },
316
+ {
317
+ timestamps: {
318
+ createdAt: false,
319
+ updatedAt: true
320
+ }
321
+ }
322
+ )
323
+
324
+ User.set('toJSON', {
325
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
326
+ transform: function (_: any, ret: any) {
327
+ ret.id = ret._id
328
+ delete ret._id
329
+ delete ret.__v
330
+ delete ret.updatedAt
331
+ },
332
+ versionKey: false,
333
+ virtuals: true
334
+ })
335
+
336
+ const UserModel = model<IUser>('users', User)
337
+
338
+ export { IUser, UserModel }
339
+ `,
340
+ file: `${projectName}/src/models/user.ts`
341
+ }
342
+ },
343
+ network: {
344
+ routes: {
345
+ content: `import { Application, Response, Request, Router, NextFunction } from 'express'
346
+ import swaggerUi from 'swagger-ui-express'
347
+ import httpErrors from 'http-errors'
348
+
349
+ import { Home, User } from '../routes'
350
+ import { response, docs } from '../utils'
351
+
352
+ const routers = [User]
353
+
354
+ const applyRoutes = (app: Application): void => {
355
+ app.use('/', Home)
356
+ app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(docs))
357
+ routers.forEach((router: Router): Application => app.use('/api', router))
358
+
359
+ // Handling 404 error
360
+ app.use((req, res, next) => {
361
+ next(new httpErrors.NotFound('This route does not exists'))
362
+ })
363
+ app.use(
364
+ (
365
+ error: httpErrors.HttpError,
366
+ req: Request,
367
+ res: Response,
368
+ next: NextFunction
369
+ ) => {
370
+ response(true, error.message, res, error.status)
371
+ next()
372
+ }
373
+ )
374
+ }
375
+
376
+ export { applyRoutes }
377
+ `,
378
+ file: `${projectName}/src/network/routes.ts`
379
+ },
380
+ server: {
381
+ content: `import express from 'express'
382
+ import mongoose from 'mongoose'
383
+ import morgan from 'morgan'
384
+
385
+ import { applyRoutes } from './routes'
386
+
387
+ const PORT = (process.env.PORT as string) || '1996'
388
+
389
+ class Server {
390
+ private _app: express.Application
391
+ private _connection: mongoose.Connection | undefined
392
+
393
+ constructor() {
394
+ this._app = express()
395
+ this._config()
396
+ }
397
+
398
+ private _config() {
399
+ this._app.set('port', PORT)
400
+ this._app.use(morgan('dev'))
401
+ this._app.use(express.json())
402
+ this._app.use(express.urlencoded({ extended: false }))
403
+ this._app.use(
404
+ (
405
+ req: express.Request,
406
+ res: express.Response,
407
+ next: express.NextFunction
408
+ ) => {
409
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
410
+ res.header('Access-Control-Allow-Origin', '*')
411
+ res.header(
412
+ 'Access-Control-Allow-Headers',
413
+ 'Authorization, Content-Type'
414
+ )
415
+ next()
416
+ }
417
+ )
418
+ applyRoutes(this._app)
419
+ }
420
+
421
+ private async _mongo(): Promise<void> {
422
+ this._connection = mongoose.connection
423
+ const connection = {
424
+ keepAlive: true,
425
+ useCreateIndex: true,
426
+ useFindAndModify: false,
427
+ useNewUrlParser: true,
428
+ useUnifiedTopology: true
429
+ }
430
+ this._connection.on('connected', () => {
431
+ console.log('Mongo connection established.')
432
+ })
433
+ this._connection.on('reconnected', () => {
434
+ console.log('Mongo connection reestablished')
435
+ })
436
+ this._connection.on('disconnected', () => {
437
+ console.log('Mongo connection disconnected')
438
+ console.log('Trying to reconnected to Mongo...')
439
+ setTimeout(() => {
440
+ mongoose.connect(process.env.MONGO_URI as string, {
441
+ ...connection,
442
+ connectTimeoutMS: 3000,
443
+ socketTimeoutMS: 3000
444
+ })
445
+ }, 3000)
446
+ })
447
+ this._connection.on('close', () => {
448
+ console.log('Mongo connection closed')
449
+ })
450
+ this._connection.on('error', (e: Error) => {
451
+ console.log('Mongo connection error:')
452
+ console.error(e)
453
+ })
454
+ await mongoose.connect(process.env.MONGO_URI as string, connection)
455
+ }
456
+
457
+ public start(): void {
458
+ this._app.listen(PORT, () => {
459
+ console.log(\`Server running at port \${PORT}\`)
460
+ })
461
+
462
+ try {
463
+ this._mongo()
464
+ } catch (e) {
465
+ console.error(e)
466
+ }
467
+ }
468
+ }
469
+
470
+ const server = new Server()
471
+
472
+ export { server as Server }
473
+ `,
474
+ file: `${projectName}/src/network/server.ts`
475
+ },
476
+ index: {
477
+ content: `import { applyRoutes } from './routes'
478
+ import { Server } from './server'
479
+
480
+ export { applyRoutes, Server }
481
+ `,
482
+ file: `${projectName}/src/network/index.ts`
483
+ }
484
+ },
485
+ routes: {
486
+ home: {
487
+ content: `import { Response, Request, Router } from 'express'
488
+ import { response } from '../utils'
489
+
490
+ const Home = Router()
491
+
492
+ Home.route('').get((req: Request, res: Response) => {
493
+ response(false, 'Welcome to your Express Backend!', res, 200)
494
+ })
495
+
496
+ export { Home }
497
+ `,
498
+ file: `${projectName}/src/routes/home.ts`
499
+ },
500
+ index: {
501
+ content: `import { Home } from './home'
502
+ import { User } from './users'
503
+
504
+ export { Home, User }
505
+ `,
506
+ file: `${projectName}/src/routes/index.ts`
507
+ },
508
+ user: {
509
+ content: `import { Router, NextFunction } from 'express'
510
+
511
+ import { Response, Request } from '../custom'
512
+ import { response } from '../utils'
513
+ import { User as UserC } from '../controllers/user'
514
+ import { DtoUser } from '../dto-interfaces'
515
+ import { idSchema, userSchema } from '../schemas'
516
+
517
+ const User = Router()
518
+
519
+ User.route('/users')
520
+ .post(
521
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
522
+ const {
523
+ body: { args }
524
+ } = req
525
+ const u = new UserC(args as DtoUser)
526
+
527
+ try {
528
+ const result = await u.process({ type: 'store' })
529
+ response(false, result, res, 201)
530
+ } catch (e) {
531
+ next(e)
532
+ }
533
+ }
534
+ )
535
+ .get(
536
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
537
+ const u = new UserC()
538
+
539
+ try {
540
+ const result = await u.process({ type: 'getAll' })
541
+ response(false, result, res, 200)
542
+ } catch (e) {
543
+ next(e)
544
+ }
545
+ }
546
+ )
547
+ .delete(
548
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
549
+ const u = new UserC()
550
+
551
+ try {
552
+ const result = await u.process({ type: 'deleteAll' })
553
+ response(false, result, res, 200)
554
+ } catch (e) {
555
+ next(e)
556
+ }
557
+ }
558
+ )
559
+
560
+ User.route('/user/:id')
561
+ .get(
562
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
563
+ const {
564
+ params: { id }
565
+ } = req
566
+
567
+ try {
568
+ await idSchema.validateAsync(id)
569
+ const u = new UserC({ id } as DtoUser)
570
+ const result = await u.process({ type: 'getOne' })
571
+ response(false, result, res, 200)
572
+ } catch (e) {
573
+ if (e.isJoi) e.status = 422
574
+ next(e)
575
+ }
576
+ }
577
+ )
578
+ .patch(
579
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
580
+ const {
581
+ body: { args },
582
+ params: { id }
583
+ } = req
584
+ const user: DtoUser = {
585
+ id,
586
+ ...args
587
+ }
588
+
589
+ try {
590
+ await userSchema.validateAsync(user)
591
+ const u = new UserC(user)
592
+ const result = await u.process({ type: 'update' })
593
+ response(false, result, res, 200)
594
+ } catch (e) {
595
+ if (e.isJoi) e.status = 422
596
+ next(e)
597
+ }
598
+ }
599
+ )
600
+ .delete(
601
+ async (req: Request, res: Response, next: NextFunction): Promise<void> => {
602
+ const {
603
+ params: { id }
604
+ } = req
605
+
606
+ try {
607
+ await idSchema.validateAsync(id)
608
+ const u = new UserC({ id } as DtoUser)
609
+ const result = await u.process({ type: 'delete' })
610
+ response(false, result, res, 200)
611
+ } catch (e) {
612
+ if (e.isJoi) e.status = 422
613
+ next(e)
614
+ }
615
+ }
616
+ )
617
+
618
+ export { User }
619
+ `,
620
+ file: `${projectName}/src/routes/users.ts`
621
+ }
622
+ },
623
+ schemas: {
624
+ index: {
625
+ content: `import Joi from 'joi'
626
+
627
+ import { userSchema } from './user'
628
+
629
+ const idSchema = Joi.string().length(24).required()
630
+
631
+ export { idSchema, userSchema }
632
+ `,
633
+ file: `${projectName}/src/schemas/index.ts`
634
+ },
635
+ user: {
636
+ content: `import Joi from 'joi'
637
+
638
+ const userSchema = Joi.object().keys({
639
+ id: Joi.string().length(24).required(),
640
+ lastName: Joi.string().required(),
641
+ name: Joi.string().required()
642
+ })
643
+
644
+ export { userSchema }
645
+ `,
646
+ file: `${projectName}/src/schemas/user.ts`
647
+ }
648
+ },
649
+ test: {
650
+ index: {
651
+ content: `### Testing store a user
652
+ POST http://localhost:1996/api/users
653
+ Content-Type: application/json
654
+
655
+ {
656
+ "args": {
657
+ "lastName": "Lzq",
658
+ "name": "Anthony"
659
+ }
660
+ }
661
+
662
+ ### Testing getAll users
663
+ GET http://localhost:1996/api/users
664
+
665
+ ### Testing deleteAll users
666
+ DELETE http://localhost:1996/api/users
667
+
668
+ ### Testing getOne user
669
+ GET http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
670
+
671
+ ### Testing update user
672
+ PATCH http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
673
+ Content-Type: application/json
674
+
675
+ {
676
+ "args": {
677
+ "name": "Anthony",
678
+ "lastName": "Luzquiños"
679
+ }
680
+ }
681
+
682
+ ### Testing delete user
683
+ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
684
+ `,
685
+ file: `${projectName}/src/test/index.http`
686
+ }
687
+ },
688
+ utils: {
689
+ docs: {
690
+ content: `{
691
+ "openapi": "3.0.0",
692
+ "info": {
693
+ "title": "${projectName}",
694
+ "description": "Documentation of the test",
695
+ "contact": {
696
+ "email": "${email}"
697
+ },
698
+ "license": {
699
+ "name": "MIT",
700
+ "url": "https://opensource.org/licenses/MIT"
701
+ },
702
+ "version": "${projectVersion}"
703
+ },
704
+ "servers": [
705
+ {
706
+ "url": "http://localhost:1996/api",
707
+ "description": "${projectName} local API"
708
+ }
709
+ ],
710
+ "tags": [
711
+ {
712
+ "name": "user",
713
+ "description": "Operations related to the user"
714
+ }
715
+ ],
716
+ "paths": {
717
+ "/users": {
718
+ "post": {
719
+ "tags": [
720
+ "user"
721
+ ],
722
+ "summary": "Save a user in the database",
723
+ "operationId": "store",
724
+ "requestBody": {
725
+ "$ref": "#/components/requestBodies/DtoUser"
726
+ },
727
+ "responses": {
728
+ "201": {
729
+ "description": "User successfully stored",
730
+ "content": {
731
+ "application/json": {
732
+ "schema": {
733
+ "$ref": "#/components/schemas/User"
734
+ }
735
+ }
736
+ }
737
+ },
738
+ "422": {
739
+ "description": "Invalid request format",
740
+ "content": {
741
+ "application/json": {
742
+ "schema": {
743
+ "$ref": "#/components/schemas/DefaultError"
744
+ }
745
+ }
746
+ }
747
+ },
748
+ "500": {
749
+ "description": "Internal server error",
750
+ "content": {
751
+ "application/json": {
752
+ "schema": {
753
+ "$ref": "#/components/schemas/DefaultError"
754
+ }
755
+ }
756
+ }
757
+ }
758
+ }
759
+ },
760
+ "get": {
761
+ "tags": [
762
+ "user"
763
+ ],
764
+ "summary": "Get all the users in the database",
765
+ "operationId": "getAll",
766
+ "responses": {
767
+ "200": {
768
+ "description": "All the users in the database",
769
+ "content": {
770
+ "application/json": {
771
+ "schema": {
772
+ "type": "object",
773
+ "properties": {
774
+ "error": {
775
+ "type": "boolean",
776
+ "default": false
777
+ },
778
+ "message": {
779
+ "type": "object",
780
+ "properties": {
781
+ "result": {
782
+ "type": "array",
783
+ "items": {
784
+ "$ref": "#/components/schemas/User"
785
+ }
786
+ }
787
+ }
788
+ }
789
+ }
790
+ }
791
+ }
792
+ }
793
+ },
794
+ "500": {
795
+ "description": "Internal server error",
796
+ "content": {
797
+ "application/json": {
798
+ "schema": {
799
+ "$ref": "#/components/schemas/DefaultError"
800
+ }
801
+ }
802
+ }
803
+ }
804
+ }
805
+ },
806
+ "delete": {
807
+ "tags": [
808
+ "user"
809
+ ],
810
+ "summary": "Delete all the users in the database",
811
+ "operationId": "deleteAll",
812
+ "responses": {
813
+ "200": {
814
+ "description": "All the users in the database",
815
+ "content": {
816
+ "application/json": {
817
+ "schema": {
818
+ "$ref": "#/components/schemas/DefaultSuccess"
819
+ }
820
+ }
821
+ }
822
+ },
823
+ "500": {
824
+ "description": "Internal server error",
825
+ "content": {
826
+ "application/json": {
827
+ "schema": {
828
+ "$ref": "#/components/schemas/DefaultError"
829
+ }
830
+ }
831
+ }
832
+ }
833
+ }
834
+ }
835
+ },
836
+ "/user/{id}": {
837
+ "get": {
838
+ "tags": [
839
+ "user"
840
+ ],
841
+ "summary": "Get an specific user",
842
+ "operationId": "getOne",
843
+ "parameters": [
844
+ {
845
+ "name": "id",
846
+ "in": "path",
847
+ "description": "MongoDB user id",
848
+ "required": true,
849
+ "style": "simple",
850
+ "explode": false,
851
+ "schema": {
852
+ "type": "string"
853
+ }
854
+ }
855
+ ],
856
+ "responses": {
857
+ "200": {
858
+ "description": "User stored in the database",
859
+ "content": {
860
+ "application/json": {
861
+ "schema": {
862
+ "$ref": "#/components/schemas/User"
863
+ }
864
+ }
865
+ }
866
+ },
867
+ "404": {
868
+ "description": "User not found",
869
+ "content": {
870
+ "application/json": {
871
+ "schema": {
872
+ "$ref": "#/components/schemas/DefaultError"
873
+ }
874
+ }
875
+ }
876
+ },
877
+ "422": {
878
+ "description": "Invalid request format",
879
+ "content": {
880
+ "application/json": {
881
+ "schema": {
882
+ "$ref": "#/components/schemas/DefaultError"
883
+ }
884
+ }
885
+ }
886
+ },
887
+ "500": {
888
+ "description": "Internal server error",
889
+ "content": {
890
+ "application/json": {
891
+ "schema": {
892
+ "$ref": "#/components/schemas/DefaultError"
893
+ }
894
+ }
895
+ }
896
+ }
897
+ }
898
+ },
899
+ "patch": {
900
+ "tags": [
901
+ "user"
902
+ ],
903
+ "summary": "Update the user data",
904
+ "operationId": "update",
905
+ "parameters": [
906
+ {
907
+ "name": "id",
908
+ "in": "path",
909
+ "description": "MongoDB user id",
910
+ "required": true,
911
+ "style": "simple",
912
+ "explode": false,
913
+ "schema": {
914
+ "type": "string"
915
+ }
916
+ }
917
+ ],
918
+ "requestBody": {
919
+ "$ref": "#/components/requestBodies/DtoUser"
920
+ },
921
+ "responses": {
922
+ "200": {
923
+ "description": "User successfully updated",
924
+ "content": {
925
+ "application/json": {
926
+ "schema": {
927
+ "$ref": "#/components/schemas/User"
928
+ }
929
+ }
930
+ }
931
+ },
932
+ "404": {
933
+ "description": "User not found",
934
+ "content": {
935
+ "application/json": {
936
+ "schema": {
937
+ "$ref": "#/components/schemas/DefaultError"
938
+ }
939
+ }
940
+ }
941
+ },
942
+ "422": {
943
+ "description": "Invalid request format",
944
+ "content": {
945
+ "application/json": {
946
+ "schema": {
947
+ "$ref": "#/components/schemas/DefaultError"
948
+ }
949
+ }
950
+ }
951
+ },
952
+ "500": {
953
+ "description": "Internal server error",
954
+ "content": {
955
+ "application/json": {
956
+ "schema": {
957
+ "$ref": "#/components/schemas/DefaultError"
958
+ }
959
+ }
960
+ }
961
+ }
962
+ }
963
+ },
964
+ "delete": {
965
+ "tags": [
966
+ "user"
967
+ ],
968
+ "summary": "Delete one user from the database",
969
+ "operationId": "delete",
970
+ "parameters": [
971
+ {
972
+ "name": "id",
973
+ "in": "path",
974
+ "description": "MongoDB user id",
975
+ "required": true,
976
+ "style": "simple",
977
+ "explode": false,
978
+ "schema": {
979
+ "type": "string"
980
+ }
981
+ }
982
+ ],
983
+ "responses": {
984
+ "200": {
985
+ "description": "User successfully deleted",
986
+ "content": {
987
+ "application/json": {
988
+ "schema": {
989
+ "$ref": "#/components/schemas/DefaultSuccess"
990
+ }
991
+ }
992
+ }
993
+ },
994
+ "404": {
995
+ "description": "User not found",
996
+ "content": {
997
+ "application/json": {
998
+ "schema": {
999
+ "$ref": "#/components/schemas/DefaultError"
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
+ }
1027
+ },
1028
+ "components": {
1029
+ "schemas": {
1030
+ "User": {
1031
+ "type": "object",
1032
+ "properties": {
1033
+ "id": {
1034
+ "type": "string"
1035
+ },
1036
+ "lastName": {
1037
+ "type": "string"
1038
+ },
1039
+ "name": {
1040
+ "type": "string"
1041
+ }
1042
+ }
1043
+ },
1044
+ "DefaultSuccess": {
1045
+ "type": "object",
1046
+ "properties": {
1047
+ "error": {
1048
+ "type": "boolean",
1049
+ "default": false
1050
+ },
1051
+ "message": {
1052
+ "type": "object",
1053
+ "properties": {
1054
+ "result": {
1055
+ "type": "string"
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+ },
1061
+ "DefaultError": {
1062
+ "type": "object",
1063
+ "properties": {
1064
+ "error": {
1065
+ "type": "boolean",
1066
+ "default": true
1067
+ },
1068
+ "message": {
1069
+ "type": "object",
1070
+ "properties": {
1071
+ "result": {
1072
+ "type": "string"
1073
+ }
1074
+ }
1075
+ }
1076
+ }
1077
+ }
1078
+ },
1079
+ "requestBodies": {
1080
+ "DtoUser": {
1081
+ "description": "User name and last name",
1082
+ "content": {
1083
+ "application/json": {
1084
+ "schema": {
1085
+ "type": "object",
1086
+ "properties": {
1087
+ "args": {
1088
+ "type": "object",
1089
+ "properties": {
1090
+ "name": {
1091
+ "type": "string"
1092
+ },
1093
+ "lastName": {
1094
+ "type": "string"
1095
+ }
1096
+ }
1097
+ }
1098
+ }
1099
+ }
1100
+ }
1101
+ },
1102
+ "required": true
1103
+ }
1104
+ }
1105
+ }
1106
+ }`,
1107
+ file: `${projectName}/src/utils/docs.json`
1108
+ },
1109
+ index: {
1110
+ content: `import docs from './docs.json'
1111
+ import { response } from './response'
1112
+
1113
+ export { docs, response }
1114
+ `,
1115
+ file: `${projectName}/src/utils/index.ts`
1116
+ },
1117
+ response: {
1118
+ content: `import { Response } from 'express'
1119
+
1120
+ const response = (
1121
+ error: boolean,
1122
+ message: unknown,
1123
+ res: Response,
1124
+ status: number
1125
+ ): void => {
1126
+ res.status(status).send({ error, message })
1127
+ }
1128
+
1129
+ export { response }
1130
+ `,
1131
+ file: `${projectName}/src/utils/response.ts`
1132
+ }
1133
+ },
1134
+ '.env': {
1135
+ content: 'MONGO_URI = ',
1136
+ file: `${projectName}/.env`
1137
+ },
1138
+ index: {
1139
+ content: `import { Server } from './network'
1140
+
1141
+ Server.start()
1142
+ `,
1143
+ file: `${projectName}/src/index.ts`
1144
+ }
1145
+ }
1146
+
1147
+ await exec(`mkdir ${projectName}/src \
1148
+ ${projectName}/src/@types \
1149
+ ${projectName}/src/controllers \
1150
+ ${projectName}/src/controllers/utils \
1151
+ ${projectName}/src/controllers/utils/messages \
1152
+ ${projectName}/src/dto-interfaces \
1153
+ ${projectName}/src/models \
1154
+ ${projectName}/src/network \
1155
+ ${projectName}/src/routes \
1156
+ ${projectName}/src/schemas \
1157
+ ${projectName}/src/test \
1158
+ ${projectName}/src/utils
1159
+ `)
1160
+
1161
+ // /@types
1162
+ await writeFile(data['@types'].index.file, data['@types'].index.content)
1163
+
1164
+ // /controllers
1165
+ await writeFile(data.controllers.user.file, data.controllers.user.content)
1166
+ await writeFile(data.controllers.index.file, data.controllers.index.content)
1167
+
1168
+ // /controllers/utils
1169
+ await writeFile(
1170
+ data['controllers/utils'].index.file,
1171
+ data['controllers/utils'].index.content
1172
+ )
1173
+
1174
+ // /controllers/utils/messages
1175
+ await writeFile(
1176
+ data['controllers/utils/messages'].user.file,
1177
+ data['controllers/utils/messages'].user.content
1178
+ )
1179
+ await writeFile(
1180
+ data['controllers/utils/messages'].index.file,
1181
+ data['controllers/utils/messages'].index.content
1182
+ )
1183
+
1184
+ // /dto-interfaces
1185
+ await writeFile(
1186
+ data['dto-interfaces'].user.file,
1187
+ data['dto-interfaces'].user.content
1188
+ )
1189
+ await writeFile(
1190
+ data['dto-interfaces'].index.file,
1191
+ data['dto-interfaces'].index.content
1192
+ )
1193
+
1194
+ // /models
1195
+ await writeFile(data.models.user.file, data.models.user.content)
1196
+ await writeFile(data.models.index.file, data.models.index.content)
1197
+
1198
+ // /network
1199
+ await writeFile(data.network.routes.file, data.network.routes.content)
1200
+ await writeFile(data.network.server.file, data.network.server.content)
1201
+ await writeFile(data.network.index.file, data.network.index.content)
1202
+
1203
+ // /routes
1204
+ await writeFile(data.routes.home.file, data.routes.home.content)
1205
+ await writeFile(data.routes.user.file, data.routes.user.content)
1206
+ await writeFile(data.routes.index.file, data.routes.index.content)
1207
+
1208
+ // /schemas
1209
+ await writeFile(data.schemas.index.file, data.schemas.index.content)
1210
+ await writeFile(data.schemas.user.file, data.schemas.user.content)
1211
+
1212
+ // /test
1213
+ await writeFile(data.test.index.file, data.test.index.content)
1214
+
1215
+ // /utils
1216
+ await writeFile(data.utils.docs.file, data.utils.docs.content)
1217
+ await writeFile(data.utils.response.file, data.utils.response.content)
1218
+ await writeFile(data.utils.index.file, data.utils.index.content)
1219
+
1220
+ // .env
1221
+ await writeFile(data['.env'].file, data['.env'].content)
1222
+
1223
+ // index
1224
+ await writeFile(data.index.file, data.index.content)
1225
+ }