@anthonylzq/simba.js 1.10.0 → 2.0.3
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 +55 -27
- package/lib/index.js +1 -1
- package/lib/src/functions/docker.js +2 -2
- package/lib/src/functions/eslint.js +1 -1
- package/lib/src/functions/express.js +445 -356
- package/lib/src/functions/tsconfig.js +38 -8
- package/lib/src/installation.js +1 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Set up a modern backend app by running one command. This project has the goal to
|
|
|
6
6
|
|
|
7
7
|
- `.env`
|
|
8
8
|
- `.eslintignore`
|
|
9
|
-
- `.eslintrc
|
|
9
|
+
- `.eslintrc`
|
|
10
10
|
- `.gitignore`
|
|
11
11
|
- `CHANGELOG.md`
|
|
12
12
|
- `Dockerfile`
|
|
@@ -15,15 +15,17 @@ Set up a modern backend app by running one command. This project has the goal to
|
|
|
15
15
|
- `nodemon.json`
|
|
16
16
|
- `package.json`
|
|
17
17
|
- `README.md`
|
|
18
|
+
- `tsconfig.base.json`
|
|
18
19
|
- `tsconfig.json`
|
|
19
20
|
- `webpack.config.js`
|
|
21
|
+
- `yarn.lock` (or `package-lock.json`)
|
|
20
22
|
|
|
21
23
|
## Installation
|
|
22
24
|
|
|
23
25
|
This package is meant to be installed globally in your computer by using:
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
|
-
npm i -g simba.js
|
|
28
|
+
npm i -g @anthonylzq/simba.js
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
## Usage
|
|
@@ -86,8 +88,8 @@ Options:
|
|
|
86
88
|
-h, --help Show help [boolean]
|
|
87
89
|
|
|
88
90
|
Examples:
|
|
89
|
-
simba
|
|
90
|
-
sluzquinosa@uni.pe
|
|
91
|
+
simba -N 'Project Name' -D 'Project description' -a Anthony -e
|
|
92
|
+
sluzquinosa@uni.pe
|
|
91
93
|
|
|
92
94
|
Developed by AnthonyLzq
|
|
93
95
|
```
|
|
@@ -95,34 +97,56 @@ Developed by AnthonyLzq
|
|
|
95
97
|
Regardless of the option chosen, a new folder will be generated with the name of the project, it will contain the following structure:
|
|
96
98
|
|
|
97
99
|
```
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
📂node_modules
|
|
101
|
+
📂src
|
|
100
102
|
┣ 📂@types
|
|
101
|
-
┃ ┣
|
|
102
|
-
┣
|
|
103
|
-
┃
|
|
104
|
-
┃
|
|
105
|
-
|
|
106
|
-
┃ ┣
|
|
107
|
-
┃ ┗ 📜user.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
┃
|
|
103
|
+
┃ ┣ 📂custom
|
|
104
|
+
┃ ┃ ┣ 📜request.d.ts
|
|
105
|
+
┃ ┃ ┗ 📜response.d.ts
|
|
106
|
+
┃ ┣ 📂dto
|
|
107
|
+
┃ ┃ ┗ 📜user.d.ts
|
|
108
|
+
┃ ┣ 📂models
|
|
109
|
+
┃ ┃ ┗ 📜user.d.ts
|
|
110
|
+
┃ ┗ 📜index.d.ts
|
|
111
|
+
┣ 📂database
|
|
112
|
+
┃ ┣ 📂mongo
|
|
113
|
+
┃ ┃ ┣ 📂models
|
|
114
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
115
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
116
|
+
┃ ┃ ┣ 📂queries
|
|
117
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
118
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
119
|
+
┃ ┃ ┗ 📜index.ts
|
|
120
|
+
┃ ┗ 📜index.ts
|
|
111
121
|
┣ 📂network
|
|
122
|
+
┃ ┣ 📂routes
|
|
123
|
+
┃ ┃ ┣ 📂schemas
|
|
124
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
125
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
126
|
+
┃ ┃ ┣ 📜home.ts
|
|
127
|
+
┃ ┃ ┣ 📜index.ts
|
|
128
|
+
┃ ┃ ┗ 📜user.ts
|
|
112
129
|
┃ ┣ 📜index.ts
|
|
130
|
+
┃ ┣ 📜response.ts
|
|
113
131
|
┃ ┣ 📜routes.ts
|
|
114
132
|
┃ ┗ 📜server.ts
|
|
115
|
-
┣ 📂
|
|
116
|
-
┃ ┣
|
|
133
|
+
┣ 📂services
|
|
134
|
+
┃ ┣ 📂utils
|
|
135
|
+
┃ ┃ ┣ 📂messages
|
|
136
|
+
┃ ┃ ┃ ┣ 📜index.ts
|
|
137
|
+
┃ ┃ ┃ ┗ 📜user.ts
|
|
138
|
+
┃ ┃ ┗ 📜index.ts
|
|
117
139
|
┃ ┣ 📜index.ts
|
|
118
140
|
┃ ┗ 📜user.ts
|
|
141
|
+
┣ 📂test
|
|
142
|
+
┃ ┗ 📜test.http
|
|
119
143
|
┣ 📂utils
|
|
120
|
-
┃ ┣ 📜
|
|
121
|
-
┃ ┗ 📜
|
|
144
|
+
┃ ┣ 📜docs.json
|
|
145
|
+
┃ ┗ 📜index.ts
|
|
122
146
|
┗ 📜index.ts
|
|
123
147
|
📜.env
|
|
124
148
|
📜.eslintignore
|
|
125
|
-
📜.eslintrc
|
|
149
|
+
📜.eslintrc
|
|
126
150
|
📜.gitignore
|
|
127
151
|
📜CHANGELOG.md
|
|
128
152
|
📜Dockerfile
|
|
@@ -131,6 +155,7 @@ Regardless of the option chosen, a new folder will be generated with the name of
|
|
|
131
155
|
📜nodemon.json
|
|
132
156
|
📜package.json
|
|
133
157
|
📜README.md
|
|
158
|
+
📜tsconfig.base.json
|
|
134
159
|
📜tsconfig.json
|
|
135
160
|
📜webpack.config.js
|
|
136
161
|
📜yarn.lock (or package-lock.json)
|
|
@@ -160,8 +185,8 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
|
|
|
160
185
|
|
|
161
186
|
### Some considerations
|
|
162
187
|
|
|
163
|
-
- This project
|
|
164
|
-
- You are able to run a server that has one main route, `home` (`/`), `user` (`api/user` or `api/user/:
|
|
188
|
+
- This project was based in other project from my own, [`typescript-project-generator`](https://www.npmjs.com/package/typescript-project-generator), but only considering the `express-mongoose` part.
|
|
189
|
+
- You are able to run a server that has one main route, `home` (`/`), `user` (`api/user` or `api/user/:id`) and `docs` (`api/docs`).
|
|
165
190
|
- To connect your server with your `MongoDB` database, you need to provide your `uri` in the `.env`. By default, Simba will try to connect to a local database. The content of the `.env` file is:
|
|
166
191
|
|
|
167
192
|
```bash
|
|
@@ -182,11 +207,16 @@ simba -N myProject -D 'This is a test' -a myName -e myEmail@email.com -H
|
|
|
182
207
|
// Some more code...
|
|
183
208
|
|
|
184
209
|
// another file
|
|
185
|
-
globalStringVariable = 'Hi mom, I am global'
|
|
210
|
+
global.globalStringVariable = 'Hi mom, I am global'
|
|
186
211
|
console.log({ globalStringVariable })
|
|
187
212
|
```
|
|
188
213
|
|
|
189
|
-
- The provided project structure is inspired in my personal experience as [`Node.js`](https://nodejs.org/en/) developer and the [`Nest`](https://nestjs.com/) framework.
|
|
214
|
+
- The provided project structure is inspired in my personal experience as [`Node.js`](https://nodejs.org/en/) developer and the [`Nest`](https://nestjs.com/) framework. It follows a layered architecture:
|
|
215
|
+
|
|
216
|
+
1. Presentation layer (network layer): it is represented by the network folder, which contains the routes and the necessary schemas for each route.
|
|
217
|
+
2. Business layer (services layer): it is represented by the services folder, which contains all the code related to the business logic of your application.
|
|
218
|
+
3. Persistance layer (database layer): it is represented by the database folder, which contains the database connection, models and queries (that will be used by the services). Multiple database connection are possible and should be implemented here.
|
|
219
|
+
|
|
190
220
|
- The server is fully tested and has no errors (at least for now), feel free to report one [here](https://github.com/AnthonyLzq/simba.js/issues).
|
|
191
221
|
- Support for windows and linux platforms is available.
|
|
192
222
|
- To check the content of the files generated, please check the `example` folder.
|
|
@@ -215,8 +245,6 @@ Here is the list of the packages that are being installed, as `devDependencies`:
|
|
|
215
245
|
- [`eslint-config-standard`](https://www.npmjs.com/package/eslint-config-standard)
|
|
216
246
|
- [`eslint-plugin-import`](https://www.npmjs.com/package/eslint-plugin-import)
|
|
217
247
|
- [`eslint-plugin-prettier`](https://www.npmjs.com/package/eslint-plugin-prettier)
|
|
218
|
-
- [`eslint-plugin-sort-keys-fix`](https://www.npmjs.com/package/eslint-plugin-sort-keys-fix)
|
|
219
|
-
- [`eslint-plugin-typescript-sort-keys`](https://www.npmjs.com/package/eslint-plugin-typescript-sort-keys)
|
|
220
248
|
- [`nodemon`](https://www.npmjs.com/package/nodemon)
|
|
221
249
|
- [`prettier`](https://www.npmjs.com/package/prettier)
|
|
222
250
|
- [`standard-version`](https://www.npmjs.com/package/standard-version)
|
package/lib/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const argv = yargs(hideBin(process.argv))
|
|
|
12
12
|
'simba [options] (if you it installed globally) or only simba if you want to be asked for the options one by one'
|
|
13
13
|
)
|
|
14
14
|
.example(
|
|
15
|
-
|
|
15
|
+
"simba -N 'Project Name' -D 'Project description' -a Anthony -e sluzquinosa@uni.pe"
|
|
16
16
|
)
|
|
17
17
|
.alias('N', 'projectName')
|
|
18
18
|
.nargs('N', 1)
|
|
@@ -14,11 +14,11 @@ COPY package.json ./
|
|
|
14
14
|
|
|
15
15
|
RUN yarn install --prod
|
|
16
16
|
|
|
17
|
-
RUN yarn add webpack webpack-node-externals -D
|
|
17
|
+
RUN yarn add webpack webpack-node-externals tsconfig-paths-webpack-plugin -D
|
|
18
18
|
|
|
19
19
|
RUN yarn build
|
|
20
20
|
|
|
21
|
-
RUN yarn remove webpack webpack-node-externals
|
|
21
|
+
RUN yarn remove webpack webpack-node-externals tsconfig-paths-webpack-plugin
|
|
22
22
|
|
|
23
23
|
COPY dist /app/dist
|
|
24
24
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const os = require('os')
|
|
1
2
|
const util = require('util')
|
|
2
3
|
const exec = util.promisify(require('child_process').exec)
|
|
3
4
|
const writeFile = require('../utils/writeFile')
|
|
@@ -5,30 +6,39 @@ const writeFile = require('../utils/writeFile')
|
|
|
5
6
|
/*
|
|
6
7
|
* src
|
|
7
8
|
* |- @types:
|
|
9
|
+
* |- |- dto:
|
|
10
|
+
* |- |- |- user: content, file
|
|
11
|
+
* |- |- models:
|
|
12
|
+
* |- |- |- user: content, file
|
|
8
13
|
* | |- index: content, file
|
|
9
|
-
* |-
|
|
10
|
-
* | |-
|
|
11
|
-
* |
|
|
14
|
+
* |- database:
|
|
15
|
+
* | |- mongo:
|
|
16
|
+
* | |- |- models:
|
|
17
|
+
* | |- |- |- index: content, file
|
|
18
|
+
* | |- |- |- user: content, file
|
|
19
|
+
* | |- |- queries:
|
|
20
|
+
* | |- |- |- index: content, file
|
|
21
|
+
* | |- |- |- user: content, file
|
|
22
|
+
* | |- |- index: content, file
|
|
23
|
+
* | |- index: content, file
|
|
24
|
+
* |- network:
|
|
25
|
+
* | |- routes:
|
|
26
|
+
* | | |- schemas:
|
|
12
27
|
* | | | |- user: content, file
|
|
13
28
|
* | | | |- index: content, file
|
|
29
|
+
* | | |- home: content, file
|
|
30
|
+
* | | |- user: content, file
|
|
14
31
|
* | | |- index: content, file
|
|
15
|
-
* | |-
|
|
16
|
-
* | |-
|
|
17
|
-
* |- dto-interfaces:
|
|
18
|
-
* | |- user: content, file
|
|
19
|
-
* | |- index: content, file
|
|
20
|
-
* |- models:
|
|
21
|
-
* | |- user: content, file
|
|
22
|
-
* | |- index: content, file
|
|
23
|
-
* |- network:
|
|
32
|
+
* | | |- response: content, file
|
|
33
|
+
* | |- router: content, file
|
|
24
34
|
* | |- server: content, file
|
|
25
|
-
* | |- routes: content, file
|
|
26
|
-
* | |- index: content, file
|
|
27
|
-
* |- routes:
|
|
28
|
-
* | |- home: content, file
|
|
29
|
-
* | |- user: content, file
|
|
30
35
|
* | |- index: content, file
|
|
31
|
-
* |-
|
|
36
|
+
* |- services:
|
|
37
|
+
* | |- utils:
|
|
38
|
+
* | | |- messages:
|
|
39
|
+
* | | | |- user: content, file
|
|
40
|
+
* | | | |- index: content, file
|
|
41
|
+
* | | |- index: content, file
|
|
32
42
|
* | |- user: content, file
|
|
33
43
|
* | |- index: content, file
|
|
34
44
|
* |- test:
|
|
@@ -50,268 +60,86 @@ module.exports = async (projectName, projectVersion, email) => {
|
|
|
50
60
|
'@types': {
|
|
51
61
|
index: {
|
|
52
62
|
content: `/* eslint-disable no-var */
|
|
53
|
-
|
|
54
|
-
import { Request, Response } from 'express'
|
|
55
|
-
|
|
56
|
-
import { DtoUser } from 'dto-interfaces'
|
|
57
|
-
|
|
58
|
-
declare global {
|
|
59
|
-
interface ResponseProps {
|
|
60
|
-
error: boolean
|
|
61
|
-
message: unknown
|
|
62
|
-
res: Response
|
|
63
|
-
status: number
|
|
64
|
-
}
|
|
65
|
-
// This variable is global, so it will be available everywhere in the code
|
|
66
|
-
var response: ({ error, message, res, status }: ResponseProps) => void
|
|
67
|
-
|
|
68
|
-
// We can personalize the response and request objects in case we need it by
|
|
69
|
-
// adding new optional attributes to this interface
|
|
70
|
-
interface CustomResponse extends Response {
|
|
71
|
-
newValue?: string
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface CustomRequest extends Request {
|
|
75
|
-
body: {
|
|
76
|
-
args?: DtoUser
|
|
77
|
-
}
|
|
78
|
-
// We can add custom headers via intersection, remember that for some reason
|
|
79
|
-
// headers must be in Snake-Pascal-Case
|
|
80
|
-
headers: IncomingHttpHeaders & {
|
|
81
|
-
'Custom-Header'?: string
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
63
|
+
declare global {}
|
|
85
64
|
|
|
86
65
|
export {}
|
|
87
66
|
`,
|
|
88
67
|
file: `${projectName}/src/@types/index.d.ts`
|
|
89
68
|
}
|
|
90
69
|
},
|
|
91
|
-
|
|
92
|
-
index: {
|
|
93
|
-
content: `import { User } from './user'
|
|
94
|
-
|
|
95
|
-
export { User }
|
|
96
|
-
`,
|
|
97
|
-
file: `${projectName}/src/controllers/index.ts`
|
|
98
|
-
},
|
|
70
|
+
'@types/dto': {
|
|
99
71
|
user: {
|
|
100
|
-
content: `
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
105
|
-
|
|
106
|
-
type Process = {
|
|
107
|
-
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
72
|
+
content: `interface DtoUser {
|
|
73
|
+
id?: string
|
|
74
|
+
lastName?: string
|
|
75
|
+
name?: string
|
|
108
76
|
}
|
|
77
|
+
`,
|
|
78
|
+
file: `${projectName}/src/@types/dto/user.d.ts`
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
'@types/custom': {
|
|
82
|
+
request: {
|
|
83
|
+
content: `type ExpressRequest = import('express').Request
|
|
109
84
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
constructor(args: DtoUser | null = null) {
|
|
114
|
-
this._args = args
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public process({
|
|
118
|
-
type
|
|
119
|
-
}: Process): Promise<string> | Promise<IUser[]> | Promise<IUser> {
|
|
120
|
-
switch (type) {
|
|
121
|
-
case 'store':
|
|
122
|
-
return this._store()
|
|
123
|
-
case 'getAll':
|
|
124
|
-
return this._getAll()
|
|
125
|
-
case 'deleteAll':
|
|
126
|
-
return this._deleteAll()
|
|
127
|
-
case 'getOne':
|
|
128
|
-
return this._getOne()
|
|
129
|
-
case 'update':
|
|
130
|
-
return this._update()
|
|
131
|
-
case 'delete':
|
|
132
|
-
return this._delete()
|
|
133
|
-
default:
|
|
134
|
-
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private async _store(): Promise<IUser> {
|
|
139
|
-
const { lastName, name } = this._args as DtoUser
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
const newUser = new UserModel({ lastName, name })
|
|
143
|
-
const result = await newUser.save()
|
|
144
|
-
|
|
145
|
-
return result
|
|
146
|
-
} catch (e) {
|
|
147
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async _getAll(): Promise<IUser[]> {
|
|
152
|
-
try {
|
|
153
|
-
const users = await UserModel.find({})
|
|
154
|
-
|
|
155
|
-
return users
|
|
156
|
-
} catch (e) {
|
|
157
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private async _deleteAll(): Promise<string> {
|
|
162
|
-
try {
|
|
163
|
-
const usersDeleted = await UserModel.deleteMany({})
|
|
164
|
-
|
|
165
|
-
if (usersDeleted.deletedCount >= 1) return MFU.ALL_USERS_DELETED
|
|
166
|
-
|
|
167
|
-
if (usersDeleted.deletedCount === 0)
|
|
168
|
-
throw new httpErrors.BadRequest(EFU.NOTHING_TO_DELETE)
|
|
169
|
-
|
|
170
|
-
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
171
|
-
} catch (e) {
|
|
172
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
private async _getOne(): Promise<IUser> {
|
|
177
|
-
const { id } = this._args as DtoUser
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
const user = await UserModel.findById(id)
|
|
181
|
-
|
|
182
|
-
if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
183
|
-
|
|
184
|
-
return user
|
|
185
|
-
} catch (e) {
|
|
186
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
187
|
-
}
|
|
85
|
+
interface CustomRequest extends ExpressRequest {
|
|
86
|
+
body: {
|
|
87
|
+
args?: DtoUser
|
|
188
88
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
const updatedUser = await UserModel.findByIdAndUpdate(
|
|
195
|
-
id,
|
|
196
|
-
{ lastName, name },
|
|
197
|
-
{ new: true }
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
201
|
-
|
|
202
|
-
return updatedUser
|
|
203
|
-
} catch (e) {
|
|
204
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
private async _delete(): Promise<string> {
|
|
209
|
-
const { id } = this._args as DtoUser
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
const deletedUser = await UserModel.findByIdAndRemove(id)
|
|
213
|
-
|
|
214
|
-
if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
215
|
-
|
|
216
|
-
return MFU.USER_DELETED
|
|
217
|
-
} catch (e) {
|
|
218
|
-
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
219
|
-
}
|
|
89
|
+
// We can add custom headers via intersection, remember that for some reason
|
|
90
|
+
// headers must be in Snake-Pascal-Case
|
|
91
|
+
headers: import('http').IncomingHttpHeaders & {
|
|
92
|
+
'Custom-Header'?: string
|
|
220
93
|
}
|
|
221
94
|
}
|
|
222
|
-
|
|
223
|
-
export { User }
|
|
224
95
|
`,
|
|
225
|
-
file: `${projectName}/src/
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
index: {
|
|
230
|
-
content: `import httpErrors from 'http-errors'
|
|
231
|
-
|
|
232
|
-
import { EFU, MFU, GE } from './messages'
|
|
233
|
-
|
|
234
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
|
-
const errorHandling = (e: any, message?: string): never => {
|
|
236
|
-
console.error(e)
|
|
237
|
-
|
|
238
|
-
if (e instanceof httpErrors.HttpError) throw e
|
|
96
|
+
file: `${projectName}/src/@types/custom/request.d.ts`
|
|
97
|
+
},
|
|
98
|
+
response: {
|
|
99
|
+
content: `type ExpressResponse = import('express').Response
|
|
239
100
|
|
|
240
|
-
|
|
101
|
+
interface CustomResponse extends ExpressResponse {
|
|
102
|
+
newValue?: string
|
|
241
103
|
}
|
|
242
|
-
|
|
243
|
-
export { EFU, MFU, GE, errorHandling }
|
|
244
104
|
`,
|
|
245
|
-
file: `${projectName}/src/
|
|
105
|
+
file: `${projectName}/src/@types/custom/response.d.ts`
|
|
246
106
|
}
|
|
247
107
|
},
|
|
248
|
-
'
|
|
249
|
-
index: {
|
|
250
|
-
content: `import { EFU, MFU } from './user'
|
|
251
|
-
|
|
252
|
-
enum GenericErrors {
|
|
253
|
-
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export { EFU, MFU, GenericErrors as GE }
|
|
257
|
-
`,
|
|
258
|
-
file: `${projectName}/src/controllers/utils/messages/index.ts`
|
|
259
|
-
},
|
|
108
|
+
'@types/models': {
|
|
260
109
|
user: {
|
|
261
|
-
content: `
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
enum MessageForUser {
|
|
267
|
-
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
268
|
-
USER_DELETED = 'The requested user was successfully deleted'
|
|
110
|
+
content: `interface IUser {
|
|
111
|
+
_id: import('mongoose').Types.ObjectId
|
|
112
|
+
name: string
|
|
113
|
+
lastName: string
|
|
114
|
+
updatedAt: Date
|
|
269
115
|
}
|
|
270
|
-
|
|
271
|
-
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
272
116
|
`,
|
|
273
|
-
file: `${projectName}/src/
|
|
117
|
+
file: `${projectName}/src/@types/models/user.d.ts`
|
|
274
118
|
}
|
|
275
119
|
},
|
|
276
|
-
|
|
120
|
+
database: {
|
|
277
121
|
index: {
|
|
278
|
-
content:
|
|
279
|
-
|
|
280
|
-
export { DtoUser }
|
|
281
|
-
`,
|
|
282
|
-
file: `${projectName}/src/dto-interfaces/index.ts`
|
|
283
|
-
},
|
|
284
|
-
user: {
|
|
285
|
-
content: `interface DtoUser {
|
|
286
|
-
id: string
|
|
287
|
-
lastName?: string
|
|
288
|
-
name?: string
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export { DtoUser }
|
|
292
|
-
`,
|
|
293
|
-
file: `${projectName}/src/dto-interfaces/user.ts`
|
|
122
|
+
content: "export * from './mongo'\n",
|
|
123
|
+
file: `${projectName}/src/database/index.ts`
|
|
294
124
|
}
|
|
295
125
|
},
|
|
296
|
-
|
|
126
|
+
'database/mongo': {
|
|
297
127
|
index: {
|
|
298
|
-
content: `
|
|
299
|
-
|
|
300
|
-
export { IUser, UserModel }
|
|
128
|
+
content: `export * from './models'
|
|
129
|
+
export * from './queries'
|
|
301
130
|
`,
|
|
302
|
-
file: `${projectName}/src/
|
|
131
|
+
file: `${projectName}/src/database/mongo/index.ts`
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
'database/mongo/models': {
|
|
135
|
+
index: {
|
|
136
|
+
content: "export * from './user'\n",
|
|
137
|
+
file: `${projectName}/src/database/mongo/models/index.ts`
|
|
303
138
|
},
|
|
304
139
|
user: {
|
|
305
|
-
content:
|
|
306
|
-
import { Document, model, Schema } from 'mongoose'
|
|
140
|
+
content: `import { model, Schema } from 'mongoose'
|
|
307
141
|
|
|
308
|
-
|
|
309
|
-
lastName: string
|
|
310
|
-
name: string
|
|
311
|
-
updatedAt: Date
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const User = new Schema(
|
|
142
|
+
const User = new Schema<IUser>(
|
|
315
143
|
{
|
|
316
144
|
lastName: {
|
|
317
145
|
required: true,
|
|
@@ -326,36 +154,98 @@ const User = new Schema(
|
|
|
326
154
|
timestamps: {
|
|
327
155
|
createdAt: false,
|
|
328
156
|
updatedAt: true
|
|
157
|
+
},
|
|
158
|
+
toJSON: {
|
|
159
|
+
transform(_, ret) {
|
|
160
|
+
ret.id = ret._id
|
|
161
|
+
delete ret._id
|
|
162
|
+
delete ret.__v
|
|
163
|
+
delete ret.updatedAt
|
|
164
|
+
},
|
|
165
|
+
versionKey: false,
|
|
166
|
+
virtuals: true
|
|
329
167
|
}
|
|
330
168
|
}
|
|
331
169
|
)
|
|
332
170
|
|
|
333
|
-
User.set('toJSON', {
|
|
334
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
335
|
-
transform: function (_: any, ret: any) {
|
|
336
|
-
ret.id = ret._id
|
|
337
|
-
delete ret._id
|
|
338
|
-
delete ret.__v
|
|
339
|
-
delete ret.updatedAt
|
|
340
|
-
},
|
|
341
|
-
versionKey: false,
|
|
342
|
-
virtuals: true
|
|
343
|
-
})
|
|
344
|
-
|
|
345
171
|
const UserModel = model<IUser>('users', User)
|
|
346
172
|
|
|
347
|
-
export {
|
|
173
|
+
export { UserModel }
|
|
174
|
+
`,
|
|
175
|
+
file: `${projectName}/src/database/mongo/models/user.ts`
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
'database/mongo/queries': {
|
|
179
|
+
index: {
|
|
180
|
+
content: "export * from './user'\n",
|
|
181
|
+
file: `${projectName}/src/database/mongo/queries/index.ts`
|
|
182
|
+
},
|
|
183
|
+
user: {
|
|
184
|
+
content: `import { UserModel } from '../models'
|
|
185
|
+
|
|
186
|
+
const store = async (userData: DtoUser): Promise<IUser> => {
|
|
187
|
+
const user = new UserModel(userData)
|
|
188
|
+
|
|
189
|
+
return await user.save()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const remove = async (
|
|
193
|
+
id: string | null = null
|
|
194
|
+
): Promise<IUser | number | null> => {
|
|
195
|
+
if (id) return await UserModel.findByIdAndRemove(id)
|
|
196
|
+
|
|
197
|
+
return (await UserModel.deleteMany({})).deletedCount
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const get = async (
|
|
201
|
+
id: string | null = null
|
|
202
|
+
): Promise<IUser[] | IUser | null> => {
|
|
203
|
+
if (id) return await UserModel.findById(id)
|
|
204
|
+
|
|
205
|
+
return await UserModel.find({})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const update = async (userData: DtoUser): Promise<IUser | null> => {
|
|
209
|
+
const { id, ...rest } = userData
|
|
210
|
+
|
|
211
|
+
return await UserModel.findByIdAndUpdate(id, rest, { new: true })
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export { store, remove, get, update }
|
|
348
215
|
`,
|
|
349
|
-
file: `${projectName}/src/
|
|
216
|
+
file: `${projectName}/src/database/mongo/queries/user.ts`
|
|
350
217
|
}
|
|
351
218
|
},
|
|
352
219
|
network: {
|
|
353
|
-
|
|
220
|
+
index: {
|
|
221
|
+
content: `export * from './routes'
|
|
222
|
+
export * from './server'
|
|
223
|
+
`,
|
|
224
|
+
file: `${projectName}/src/network/index.ts`
|
|
225
|
+
},
|
|
226
|
+
response: {
|
|
227
|
+
content: `interface ResponseProps {
|
|
228
|
+
error: boolean
|
|
229
|
+
message: unknown
|
|
230
|
+
res: CustomResponse
|
|
231
|
+
status: number
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const response = ({ error, message, res, status }: ResponseProps): void => {
|
|
235
|
+
res.status(status).send({ error, message })
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export { response }
|
|
239
|
+
`,
|
|
240
|
+
file: `${projectName}/src/network/response.ts`
|
|
241
|
+
},
|
|
242
|
+
router: {
|
|
354
243
|
content: `import { Application, Response, Request, Router, NextFunction } from 'express'
|
|
355
244
|
import swaggerUi from 'swagger-ui-express'
|
|
356
245
|
import httpErrors from 'http-errors'
|
|
357
246
|
|
|
358
|
-
import {
|
|
247
|
+
import { response } from './response'
|
|
248
|
+
import { Home, User } from './routes'
|
|
359
249
|
import { docs } from 'utils'
|
|
360
250
|
|
|
361
251
|
const routers = [User]
|
|
@@ -389,14 +279,14 @@ const applyRoutes = (app: Application): void => {
|
|
|
389
279
|
|
|
390
280
|
export { applyRoutes }
|
|
391
281
|
`,
|
|
392
|
-
file: `${projectName}/src/network/
|
|
282
|
+
file: `${projectName}/src/network/router.ts`
|
|
393
283
|
},
|
|
394
284
|
server: {
|
|
395
285
|
content: `import express from 'express'
|
|
396
286
|
import mongoose from 'mongoose'
|
|
397
287
|
import morgan from 'morgan'
|
|
398
288
|
|
|
399
|
-
import { applyRoutes } from './
|
|
289
|
+
import { applyRoutes } from './router'
|
|
400
290
|
|
|
401
291
|
const PORT = (process.env.PORT as string) || '1996'
|
|
402
292
|
|
|
@@ -430,16 +320,6 @@ class Server {
|
|
|
430
320
|
}
|
|
431
321
|
)
|
|
432
322
|
|
|
433
|
-
// setting up the global response
|
|
434
|
-
global.response = ({
|
|
435
|
-
error,
|
|
436
|
-
message,
|
|
437
|
-
res,
|
|
438
|
-
status
|
|
439
|
-
}: ResponseProps): void => {
|
|
440
|
-
res.status(status).send({ error, message })
|
|
441
|
-
}
|
|
442
|
-
|
|
443
323
|
applyRoutes(this._app)
|
|
444
324
|
}
|
|
445
325
|
|
|
@@ -495,20 +375,14 @@ const server = new Server()
|
|
|
495
375
|
export { server as Server }
|
|
496
376
|
`,
|
|
497
377
|
file: `${projectName}/src/network/server.ts`
|
|
498
|
-
},
|
|
499
|
-
index: {
|
|
500
|
-
content: `import { applyRoutes } from './routes'
|
|
501
|
-
import { Server } from './server'
|
|
502
|
-
|
|
503
|
-
export { applyRoutes, Server }
|
|
504
|
-
`,
|
|
505
|
-
file: `${projectName}/src/network/index.ts`
|
|
506
378
|
}
|
|
507
379
|
},
|
|
508
|
-
routes: {
|
|
380
|
+
'network/routes': {
|
|
509
381
|
home: {
|
|
510
382
|
content: `import { Response, Request, Router } from 'express'
|
|
511
383
|
|
|
384
|
+
import { response } from 'network/response'
|
|
385
|
+
|
|
512
386
|
const Home = Router()
|
|
513
387
|
|
|
514
388
|
Home.route('').get((req: Request, res: Response) => {
|
|
@@ -522,24 +396,22 @@ Home.route('').get((req: Request, res: Response) => {
|
|
|
522
396
|
|
|
523
397
|
export { Home }
|
|
524
398
|
`,
|
|
525
|
-
file: `${projectName}/src/routes/home.ts`
|
|
399
|
+
file: `${projectName}/src/network/routes/home.ts`
|
|
526
400
|
},
|
|
527
401
|
index: {
|
|
528
|
-
content: `
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
export { Home, User }
|
|
402
|
+
content: `export * from './home'
|
|
403
|
+
export * from './user'
|
|
532
404
|
`,
|
|
533
|
-
file: `${projectName}/src/routes/index.ts`
|
|
405
|
+
file: `${projectName}/src/network/routes/index.ts`
|
|
534
406
|
},
|
|
535
407
|
user: {
|
|
536
408
|
content: `import { Router, NextFunction } from 'express'
|
|
537
409
|
import httpErrors from 'http-errors'
|
|
538
410
|
import { ValidationError } from 'joi'
|
|
539
411
|
|
|
540
|
-
import {
|
|
541
|
-
import {
|
|
542
|
-
import { idSchema, userSchema } from 'schemas'
|
|
412
|
+
import { response } from 'network/response'
|
|
413
|
+
import { UserService } from 'services/user'
|
|
414
|
+
import { idSchema, userSchema } from './schemas'
|
|
543
415
|
|
|
544
416
|
const User = Router()
|
|
545
417
|
|
|
@@ -553,10 +425,10 @@ User.route('/users')
|
|
|
553
425
|
const {
|
|
554
426
|
body: { args }
|
|
555
427
|
} = req
|
|
556
|
-
const
|
|
428
|
+
const us = new UserService(args as DtoUser)
|
|
557
429
|
|
|
558
430
|
try {
|
|
559
|
-
const result = await
|
|
431
|
+
const result = await us.process({ type: 'store' })
|
|
560
432
|
response({ error: false, message: result, res, status: 201 })
|
|
561
433
|
} catch (e) {
|
|
562
434
|
next(e)
|
|
@@ -569,10 +441,10 @@ User.route('/users')
|
|
|
569
441
|
res: CustomResponse,
|
|
570
442
|
next: NextFunction
|
|
571
443
|
): Promise<void> => {
|
|
572
|
-
const
|
|
444
|
+
const us = new UserService()
|
|
573
445
|
|
|
574
446
|
try {
|
|
575
|
-
const result = await
|
|
447
|
+
const result = await us.process({ type: 'getAll' })
|
|
576
448
|
response({ error: false, message: result, res, status: 200 })
|
|
577
449
|
} catch (e) {
|
|
578
450
|
next(e)
|
|
@@ -585,10 +457,10 @@ User.route('/users')
|
|
|
585
457
|
res: CustomResponse,
|
|
586
458
|
next: NextFunction
|
|
587
459
|
): Promise<void> => {
|
|
588
|
-
const
|
|
460
|
+
const us = new UserService()
|
|
589
461
|
|
|
590
462
|
try {
|
|
591
|
-
const result = await
|
|
463
|
+
const result = await us.process({ type: 'deleteAll' })
|
|
592
464
|
response({ error: false, message: result, res, status: 200 })
|
|
593
465
|
} catch (e) {
|
|
594
466
|
next(e)
|
|
@@ -609,8 +481,8 @@ User.route('/user/:id')
|
|
|
609
481
|
|
|
610
482
|
try {
|
|
611
483
|
await idSchema.validateAsync(id)
|
|
612
|
-
const
|
|
613
|
-
const result = await
|
|
484
|
+
const us = new UserService({ id } as DtoUser)
|
|
485
|
+
const result = await us.process({ type: 'getOne' })
|
|
614
486
|
response({ error: false, message: result, res, status: 200 })
|
|
615
487
|
} catch (e) {
|
|
616
488
|
if (e instanceof ValidationError)
|
|
@@ -637,8 +509,8 @@ User.route('/user/:id')
|
|
|
637
509
|
|
|
638
510
|
try {
|
|
639
511
|
await userSchema.validateAsync(user)
|
|
640
|
-
const
|
|
641
|
-
const result = await
|
|
512
|
+
const us = new UserService(user)
|
|
513
|
+
const result = await us.process({ type: 'update' })
|
|
642
514
|
response({ error: false, message: result, res, status: 200 })
|
|
643
515
|
} catch (e) {
|
|
644
516
|
if (e instanceof ValidationError)
|
|
@@ -660,8 +532,8 @@ User.route('/user/:id')
|
|
|
660
532
|
|
|
661
533
|
try {
|
|
662
534
|
await idSchema.validateAsync(id)
|
|
663
|
-
const
|
|
664
|
-
const result = await
|
|
535
|
+
const us = new UserService({ id } as DtoUser)
|
|
536
|
+
const result = await us.process({ type: 'delete' })
|
|
665
537
|
response({ error: false, message: result, res, status: 200 })
|
|
666
538
|
} catch (e) {
|
|
667
539
|
if (e instanceof ValidationError)
|
|
@@ -674,20 +546,19 @@ User.route('/user/:id')
|
|
|
674
546
|
|
|
675
547
|
export { User }
|
|
676
548
|
`,
|
|
677
|
-
file: `${projectName}/src/routes/user.ts`
|
|
549
|
+
file: `${projectName}/src/network/routes/user.ts`
|
|
678
550
|
}
|
|
679
551
|
},
|
|
680
|
-
schemas: {
|
|
552
|
+
'network/routes/schemas': {
|
|
681
553
|
index: {
|
|
682
554
|
content: `import Joi from 'joi'
|
|
683
555
|
|
|
684
|
-
import { userSchema } from './user'
|
|
685
|
-
|
|
686
556
|
const idSchema = Joi.string().length(24).required()
|
|
687
557
|
|
|
688
|
-
export { idSchema
|
|
558
|
+
export { idSchema }
|
|
559
|
+
export * from './user'
|
|
689
560
|
`,
|
|
690
|
-
file: `${projectName}/src/schemas/index.ts`
|
|
561
|
+
file: `${projectName}/src/network/routes/schemas/index.ts`
|
|
691
562
|
},
|
|
692
563
|
user: {
|
|
693
564
|
content: `import Joi from 'joi'
|
|
@@ -700,7 +571,175 @@ const userSchema = Joi.object().keys({
|
|
|
700
571
|
|
|
701
572
|
export { userSchema }
|
|
702
573
|
`,
|
|
703
|
-
file: `${projectName}/src/schemas/user.ts`
|
|
574
|
+
file: `${projectName}/src/network/routes/schemas/user.ts`
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
services: {
|
|
578
|
+
index: {
|
|
579
|
+
content: "export * from './user'\n",
|
|
580
|
+
file: `${projectName}/src/services/index.ts`
|
|
581
|
+
},
|
|
582
|
+
user: {
|
|
583
|
+
content: `import httpErrors from 'http-errors'
|
|
584
|
+
|
|
585
|
+
import { store, remove, get, update } from 'database'
|
|
586
|
+
import { EFU, MFU, GE, errorHandling } from './utils'
|
|
587
|
+
|
|
588
|
+
type Process = {
|
|
589
|
+
type: 'store' | 'getAll' | 'deleteAll' | 'getOne' | 'update' | 'delete'
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
class UserService {
|
|
593
|
+
private _args: DtoUser | null
|
|
594
|
+
|
|
595
|
+
constructor(args: DtoUser | null = null) {
|
|
596
|
+
this._args = args
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
public process({ type }: Process): Promise<string | IUser[] | IUser> {
|
|
600
|
+
switch (type) {
|
|
601
|
+
case 'store':
|
|
602
|
+
return this._store()
|
|
603
|
+
case 'getAll':
|
|
604
|
+
return this._getAll()
|
|
605
|
+
case 'deleteAll':
|
|
606
|
+
return this._deleteAll()
|
|
607
|
+
case 'getOne':
|
|
608
|
+
return this._getOne()
|
|
609
|
+
case 'update':
|
|
610
|
+
return this._update()
|
|
611
|
+
case 'delete':
|
|
612
|
+
return this._delete()
|
|
613
|
+
default:
|
|
614
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
private async _store(): Promise<IUser> {
|
|
619
|
+
try {
|
|
620
|
+
const result = await store(this._args as DtoUser)
|
|
621
|
+
|
|
622
|
+
return result
|
|
623
|
+
} catch (e) {
|
|
624
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
private async _getAll(): Promise<IUser[]> {
|
|
629
|
+
try {
|
|
630
|
+
const users = (await get()) as IUser[]
|
|
631
|
+
|
|
632
|
+
return users
|
|
633
|
+
} catch (e) {
|
|
634
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
private async _deleteAll(): Promise<string> {
|
|
639
|
+
try {
|
|
640
|
+
const usersDeleted = (await remove()) as number
|
|
641
|
+
|
|
642
|
+
if (usersDeleted >= 1) return MFU.ALL_USERS_DELETED
|
|
643
|
+
|
|
644
|
+
if (usersDeleted === 0)
|
|
645
|
+
throw new httpErrors.Conflict(EFU.NOTHING_TO_DELETE)
|
|
646
|
+
|
|
647
|
+
throw new httpErrors.InternalServerError(GE.INTERNAL_SERVER_ERROR)
|
|
648
|
+
} catch (e) {
|
|
649
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
private async _getOne(): Promise<IUser> {
|
|
654
|
+
const { id } = this._args as DtoUser
|
|
655
|
+
|
|
656
|
+
try {
|
|
657
|
+
const user = (await get(id as string)) as IUser | null
|
|
658
|
+
|
|
659
|
+
if (!user) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
660
|
+
|
|
661
|
+
return user
|
|
662
|
+
} catch (e) {
|
|
663
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
private async _update(): Promise<IUser> {
|
|
668
|
+
try {
|
|
669
|
+
const updatedUser = await update(this._args as DtoUser)
|
|
670
|
+
|
|
671
|
+
if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
672
|
+
|
|
673
|
+
return updatedUser
|
|
674
|
+
} catch (e) {
|
|
675
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
private async _delete(): Promise<string> {
|
|
680
|
+
const { id } = this._args as DtoUser
|
|
681
|
+
|
|
682
|
+
try {
|
|
683
|
+
const deletedUser = await remove(id)
|
|
684
|
+
|
|
685
|
+
if (!deletedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
|
|
686
|
+
|
|
687
|
+
return MFU.USER_DELETED
|
|
688
|
+
} catch (e) {
|
|
689
|
+
return errorHandling(e, GE.INTERNAL_SERVER_ERROR)
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export { UserService }
|
|
695
|
+
`,
|
|
696
|
+
file: `${projectName}/src/services/user.ts`
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
'services/utils': {
|
|
700
|
+
index: {
|
|
701
|
+
content: `import httpErrors from 'http-errors'
|
|
702
|
+
|
|
703
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
704
|
+
const errorHandling = (e: any, message?: string): never => {
|
|
705
|
+
console.error(e)
|
|
706
|
+
|
|
707
|
+
if (e instanceof httpErrors.HttpError) throw e
|
|
708
|
+
|
|
709
|
+
throw new httpErrors.InternalServerError(message ?? e.message)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export { errorHandling }
|
|
713
|
+
export * from './messages'
|
|
714
|
+
`,
|
|
715
|
+
file: `${projectName}/src/services/utils/index.ts`
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
'services/utils/messages': {
|
|
719
|
+
index: {
|
|
720
|
+
content: `enum GenericErrors {
|
|
721
|
+
INTERNAL_SERVER_ERROR = 'Something went wrong'
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
export { GenericErrors as GE }
|
|
725
|
+
export * from './user'
|
|
726
|
+
`,
|
|
727
|
+
file: `${projectName}/src/services/utils/messages/index.ts`
|
|
728
|
+
},
|
|
729
|
+
user: {
|
|
730
|
+
content: `enum ErrorForUser {
|
|
731
|
+
NOT_FOUND = 'The requested user does not exists',
|
|
732
|
+
NOTHING_TO_DELETE = 'There is no user to be deleted'
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
enum MessageForUser {
|
|
736
|
+
ALL_USERS_DELETED = 'All the users were deleted successfully',
|
|
737
|
+
USER_DELETED = 'The requested user was successfully deleted'
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export { ErrorForUser as EFU, MessageForUser as MFU }
|
|
741
|
+
`,
|
|
742
|
+
file: `${projectName}/src/services/utils/messages/user.ts`
|
|
704
743
|
}
|
|
705
744
|
},
|
|
706
745
|
test: {
|
|
@@ -1164,10 +1203,7 @@ DELETE http://localhost:1996/api/user/60e7e3b93b01c1a7aa74cd6b
|
|
|
1164
1203
|
file: `${projectName}/src/utils/docs.json`
|
|
1165
1204
|
},
|
|
1166
1205
|
index: {
|
|
1167
|
-
content:
|
|
1168
|
-
|
|
1169
|
-
export { docs }
|
|
1170
|
-
`,
|
|
1206
|
+
content: "export { default as docs } from './docs.json'\n",
|
|
1171
1207
|
file: `${projectName}/src/utils/index.ts`
|
|
1172
1208
|
}
|
|
1173
1209
|
},
|
|
@@ -1184,70 +1220,123 @@ Server.start()
|
|
|
1184
1220
|
}
|
|
1185
1221
|
}
|
|
1186
1222
|
|
|
1187
|
-
|
|
1223
|
+
const createFoldersCommands = `mkdir ${projectName}/src \
|
|
1188
1224
|
${projectName}/src/@types \
|
|
1189
|
-
${projectName}/src/
|
|
1190
|
-
${projectName}/src/
|
|
1191
|
-
${projectName}/src/
|
|
1192
|
-
${projectName}/src/
|
|
1193
|
-
${projectName}/src/
|
|
1225
|
+
${projectName}/src/@types/dto \
|
|
1226
|
+
${projectName}/src/@types/custom \
|
|
1227
|
+
${projectName}/src/@types/models \
|
|
1228
|
+
${projectName}/src/services \
|
|
1229
|
+
${projectName}/src/services/utils \
|
|
1230
|
+
${projectName}/src/services/utils/messages \
|
|
1231
|
+
${projectName}/src/database \
|
|
1232
|
+
${projectName}/src/database/mongo \
|
|
1233
|
+
${projectName}/src/database/mongo/models \
|
|
1234
|
+
${projectName}/src/database/mongo/queries \
|
|
1194
1235
|
${projectName}/src/network \
|
|
1195
|
-
${projectName}/src/routes \
|
|
1196
|
-
${projectName}/src/schemas \
|
|
1236
|
+
${projectName}/src/network/routes \
|
|
1237
|
+
${projectName}/src/network/routes/schemas \
|
|
1197
1238
|
${projectName}/src/test \
|
|
1198
1239
|
${projectName}/src/utils
|
|
1199
|
-
`
|
|
1240
|
+
`
|
|
1241
|
+
|
|
1242
|
+
if (os.platform() === 'win32')
|
|
1243
|
+
await exec(createFoldersCommands.replaceAll('/', '\\'))
|
|
1244
|
+
else await exec(createFoldersCommands)
|
|
1200
1245
|
|
|
1201
1246
|
// /@types
|
|
1202
1247
|
await writeFile(data['@types'].index.file, data['@types'].index.content)
|
|
1203
1248
|
|
|
1204
|
-
// /
|
|
1205
|
-
await writeFile(
|
|
1206
|
-
|
|
1249
|
+
// /@types/custom
|
|
1250
|
+
await writeFile(
|
|
1251
|
+
data['@types/custom'].request.file,
|
|
1252
|
+
data['@types/custom'].request.content
|
|
1253
|
+
)
|
|
1254
|
+
await writeFile(
|
|
1255
|
+
data['@types/custom'].response.file,
|
|
1256
|
+
data['@types/custom'].response.content
|
|
1257
|
+
)
|
|
1258
|
+
|
|
1259
|
+
// /@types/dto
|
|
1260
|
+
await writeFile(data['@types/dto'].user.file, data['@types/dto'].user.content)
|
|
1207
1261
|
|
|
1208
|
-
// /
|
|
1262
|
+
// /@types/models
|
|
1209
1263
|
await writeFile(
|
|
1210
|
-
data['
|
|
1211
|
-
data['
|
|
1264
|
+
data['@types/models'].user.file,
|
|
1265
|
+
data['@types/models'].user.content
|
|
1212
1266
|
)
|
|
1213
1267
|
|
|
1214
|
-
// /
|
|
1268
|
+
// /services
|
|
1269
|
+
await writeFile(data.services.user.file, data.services.user.content)
|
|
1270
|
+
await writeFile(data.services.index.file, data.services.index.content)
|
|
1271
|
+
|
|
1272
|
+
// /database
|
|
1273
|
+
await writeFile(data.database.index.file, data.database.index.content)
|
|
1215
1274
|
await writeFile(
|
|
1216
|
-
data['
|
|
1217
|
-
data['
|
|
1275
|
+
data['database/mongo'].index.file,
|
|
1276
|
+
data['database/mongo'].index.content
|
|
1218
1277
|
)
|
|
1219
1278
|
await writeFile(
|
|
1220
|
-
data['
|
|
1221
|
-
data['
|
|
1279
|
+
data['database/mongo/models'].index.file,
|
|
1280
|
+
data['database/mongo/models'].index.content
|
|
1222
1281
|
)
|
|
1223
|
-
|
|
1224
|
-
// /dto-interfaces
|
|
1225
1282
|
await writeFile(
|
|
1226
|
-
data['
|
|
1227
|
-
data['
|
|
1283
|
+
data['database/mongo/models'].user.file,
|
|
1284
|
+
data['database/mongo/models'].user.content
|
|
1228
1285
|
)
|
|
1229
1286
|
await writeFile(
|
|
1230
|
-
data['
|
|
1231
|
-
data['
|
|
1287
|
+
data['database/mongo/queries'].index.file,
|
|
1288
|
+
data['database/mongo/queries'].index.content
|
|
1289
|
+
)
|
|
1290
|
+
await writeFile(
|
|
1291
|
+
data['database/mongo/queries'].user.file,
|
|
1292
|
+
data['database/mongo/queries'].user.content
|
|
1232
1293
|
)
|
|
1233
1294
|
|
|
1234
|
-
// /
|
|
1235
|
-
await writeFile(
|
|
1236
|
-
|
|
1295
|
+
// /services/utils
|
|
1296
|
+
await writeFile(
|
|
1297
|
+
data['services/utils'].index.file,
|
|
1298
|
+
data['services/utils'].index.content
|
|
1299
|
+
)
|
|
1300
|
+
|
|
1301
|
+
// /services/utils/messages
|
|
1302
|
+
await writeFile(
|
|
1303
|
+
data['services/utils/messages'].user.file,
|
|
1304
|
+
data['services/utils/messages'].user.content
|
|
1305
|
+
)
|
|
1306
|
+
await writeFile(
|
|
1307
|
+
data['services/utils/messages'].index.file,
|
|
1308
|
+
data['services/utils/messages'].index.content
|
|
1309
|
+
)
|
|
1237
1310
|
|
|
1238
1311
|
// /network
|
|
1239
|
-
await writeFile(data.network.routes.file, data.network.routes.content)
|
|
1240
|
-
await writeFile(data.network.server.file, data.network.server.content)
|
|
1241
1312
|
await writeFile(data.network.index.file, data.network.index.content)
|
|
1313
|
+
await writeFile(data.network.response.file, data.network.response.content)
|
|
1314
|
+
await writeFile(data.network.router.file, data.network.router.content)
|
|
1315
|
+
await writeFile(data.network.server.file, data.network.server.content)
|
|
1242
1316
|
|
|
1243
|
-
// /routes
|
|
1244
|
-
await writeFile(
|
|
1245
|
-
|
|
1246
|
-
|
|
1317
|
+
// /network/routes
|
|
1318
|
+
await writeFile(
|
|
1319
|
+
data['network/routes'].home.file,
|
|
1320
|
+
data['network/routes'].home.content
|
|
1321
|
+
)
|
|
1322
|
+
await writeFile(
|
|
1323
|
+
data['network/routes'].user.file,
|
|
1324
|
+
data['network/routes'].user.content
|
|
1325
|
+
)
|
|
1326
|
+
await writeFile(
|
|
1327
|
+
data['network/routes'].index.file,
|
|
1328
|
+
data['network/routes'].index.content
|
|
1329
|
+
)
|
|
1247
1330
|
|
|
1248
|
-
// /schemas
|
|
1249
|
-
await writeFile(
|
|
1250
|
-
|
|
1331
|
+
// /network/routes/schemas
|
|
1332
|
+
await writeFile(
|
|
1333
|
+
data['network/routes/schemas'].index.file,
|
|
1334
|
+
data['network/routes/schemas'].index.content
|
|
1335
|
+
)
|
|
1336
|
+
await writeFile(
|
|
1337
|
+
data['network/routes/schemas'].user.file,
|
|
1338
|
+
data['network/routes/schemas'].user.content
|
|
1339
|
+
)
|
|
1251
1340
|
|
|
1252
1341
|
// /test
|
|
1253
1342
|
await writeFile(data.test.index.file, data.test.index.content)
|
|
@@ -6,7 +6,8 @@ const writeFile = require('../utils/writeFile')
|
|
|
6
6
|
*/
|
|
7
7
|
module.exports = async projectName => {
|
|
8
8
|
const data = {
|
|
9
|
-
|
|
9
|
+
base: {
|
|
10
|
+
content: `{
|
|
10
11
|
"ts-node": {
|
|
11
12
|
"files": true,
|
|
12
13
|
"require": ["tsconfig-paths/register"]
|
|
@@ -25,8 +26,8 @@ module.exports = async projectName => {
|
|
|
25
26
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
26
27
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
27
28
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
28
|
-
"outDir": "
|
|
29
|
-
"rootDir": "
|
|
29
|
+
"outDir": "dist" /* Redirect output structure to the directory. */,
|
|
30
|
+
"rootDir": "src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
|
30
31
|
// "composite": true, /* Enable project compilation */
|
|
31
32
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
32
33
|
// "removeComments": true, /* Do not emit comments to output. */
|
|
@@ -53,7 +54,7 @@ module.exports = async projectName => {
|
|
|
53
54
|
|
|
54
55
|
/* Module Resolution Options */
|
|
55
56
|
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
|
56
|
-
"baseUrl": "
|
|
57
|
+
"baseUrl": "src", /* Base directory to resolve non-absolute module names. */
|
|
57
58
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
58
59
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
59
60
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
@@ -79,12 +80,41 @@ module.exports = async projectName => {
|
|
|
79
80
|
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
|
80
81
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
|
81
82
|
},
|
|
82
|
-
"include": [
|
|
83
|
-
|
|
83
|
+
"include": [
|
|
84
|
+
"src",
|
|
85
|
+
"test",
|
|
86
|
+
"tests",
|
|
87
|
+
"__test__"
|
|
88
|
+
],
|
|
89
|
+
"exclude": [
|
|
90
|
+
"node_modules"
|
|
91
|
+
]
|
|
84
92
|
}
|
|
85
93
|
`,
|
|
86
|
-
|
|
94
|
+
file: 'tsconfig.base.json'
|
|
95
|
+
},
|
|
96
|
+
prod: {
|
|
97
|
+
content: `{
|
|
98
|
+
"compilerOptions": {
|
|
99
|
+
"rootDir": "src"
|
|
100
|
+
},
|
|
101
|
+
"extends": "./tsconfig.base.json",
|
|
102
|
+
"exclude": [
|
|
103
|
+
"node_modules",
|
|
104
|
+
"test",
|
|
105
|
+
"tests",
|
|
106
|
+
"__test__",
|
|
107
|
+
"dist"
|
|
108
|
+
],
|
|
109
|
+
"include": [
|
|
110
|
+
"src"
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
`,
|
|
114
|
+
file: 'tsconfig.json'
|
|
115
|
+
}
|
|
87
116
|
}
|
|
88
117
|
|
|
89
|
-
await writeFile(`${projectName}/${data.
|
|
118
|
+
await writeFile(`${projectName}/${data.base.file}`, data.base.content)
|
|
119
|
+
await writeFile(`${projectName}/${data.prod.file}`, data.prod.content)
|
|
90
120
|
}
|
package/lib/src/installation.js
CHANGED
|
@@ -56,7 +56,7 @@ module.exports = async ({
|
|
|
56
56
|
cliProgress.Presets.shades_classic
|
|
57
57
|
)
|
|
58
58
|
|
|
59
|
-
const prodPackages = `${manager} express
|
|
59
|
+
const prodPackages = `${manager} express http-errors joi mongoose morgan swagger-ui-express`
|
|
60
60
|
const devPackages = `${manager} -D \
|
|
61
61
|
@types/express \
|
|
62
62
|
@types/http-errors \
|
|
@@ -71,8 +71,6 @@ eslint-config-prettier \
|
|
|
71
71
|
eslint-config-standard \
|
|
72
72
|
eslint-plugin-import \
|
|
73
73
|
eslint-plugin-prettier \
|
|
74
|
-
eslint-plugin-sort-keys-fix \
|
|
75
|
-
eslint-plugin-typescript-sort-keys \
|
|
76
74
|
nodemon \
|
|
77
75
|
prettier \
|
|
78
76
|
standard-version \
|