express-generator-typescript 2.5.11 → 2.5.14
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/bin/cli.js +8 -26
- package/lib/cli.js +3 -1
- package/lib/express-generator-typescript.js +9 -3
- package/lib/project-files/spec/support/index.ts +32 -10
- package/lib/project-files/spec/tests/users.spec.ts +81 -112
- package/lib/project-files/src/common/route-errors.ts +8 -24
- package/lib/project-files/src/index.ts +3 -3
- package/lib/project-files/src/repos/MockOrm.ts +7 -1
- package/lib/project-files/src/repos/UserRepo.ts +25 -0
- package/lib/project-files/src/repos/database.test.json +1 -0
- package/lib/project-files/src/routes/common/index.ts +33 -19
- package/lib/project-files/src/server.ts +4 -4
- package/package.json +1 -1
- package/lib/project-files/spec/types/misc.ts +0 -13
- package/lib/project-files/spec/types/supertest/index.d.ts +0 -14
- /package/lib/project-files/src/common/{Env.ts → ENV.ts} +0 -0
package/bin/cli.js
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* created by Sean Maxwell, 5/31/2019
|
|
7
|
-
*/
|
|
3
|
+
const path = require('path'),
|
|
4
|
+
expressGenTs = require('../lib/express-generator-typescript');
|
|
8
5
|
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const expressGenTs = require('../lib/express-generator-typescript');
|
|
11
6
|
|
|
7
|
+
/******************************************************************************
|
|
8
|
+
Run
|
|
9
|
+
******************************************************************************/
|
|
12
10
|
|
|
13
|
-
//
|
|
14
|
-
|
|
11
|
+
// Init
|
|
15
12
|
console.log('Setting up new Express/TypeScript project...');
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// **** Process Options **** //
|
|
19
|
-
|
|
20
13
|
const args = process.argv.slice(2);
|
|
21
14
|
|
|
22
15
|
// Setup use yarn
|
|
@@ -27,14 +20,6 @@ if (useYarnIdx > -1) {
|
|
|
27
20
|
args.splice(useYarnIdx, 1);
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
// Setup include authentication
|
|
31
|
-
let withAuth = false;
|
|
32
|
-
const withAuthIdx = args.indexOf('--with-auth');
|
|
33
|
-
if (withAuthIdx > -1) {
|
|
34
|
-
withAuth = true;
|
|
35
|
-
args.splice(withAuthIdx, 1);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
23
|
// Setup destination
|
|
39
24
|
let destination = 'express-gen-ts';
|
|
40
25
|
if (args.length > 0) {
|
|
@@ -42,10 +27,7 @@ if (args.length > 0) {
|
|
|
42
27
|
}
|
|
43
28
|
destination = path.join(process.cwd(), destination);
|
|
44
29
|
|
|
45
|
-
|
|
46
|
-
// **** Call the generator script **** //
|
|
47
|
-
|
|
48
30
|
// Creating new project finished
|
|
49
|
-
expressGenTs(destination, useYarn
|
|
31
|
+
expressGenTs(destination, useYarn).then(() => {
|
|
50
32
|
console.log('Project setup complete!');
|
|
51
33
|
});
|
package/lib/cli.js
CHANGED
|
@@ -4,7 +4,9 @@ const path = require('path'),
|
|
|
4
4
|
expressGenTs = require('../lib/express-generator-typescript');
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/******************************************************************************
|
|
8
|
+
Run
|
|
9
|
+
******************************************************************************/
|
|
8
10
|
|
|
9
11
|
// Init
|
|
10
12
|
console.log('Setting up new Express/TypeScript project...');
|
|
@@ -5,7 +5,9 @@ const path = require('path'),
|
|
|
5
5
|
fs = require('fs');
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/******************************************************************************
|
|
9
|
+
Variables
|
|
10
|
+
******************************************************************************/
|
|
9
11
|
|
|
10
12
|
// Project folder paths
|
|
11
13
|
const PROJECT_FOLDER_PATH = './project-files';
|
|
@@ -28,7 +30,9 @@ const ncpOpts = {
|
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
/******************************************************************************
|
|
34
|
+
Functions
|
|
35
|
+
******************************************************************************/
|
|
32
36
|
|
|
33
37
|
/**
|
|
34
38
|
* Entry point
|
|
@@ -105,6 +109,8 @@ function downloadNodeModules(destination, useYarn) {
|
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
/******************************************************************************
|
|
113
|
+
Export
|
|
114
|
+
******************************************************************************/
|
|
109
115
|
|
|
110
116
|
module.exports = expressGenTs;
|
|
@@ -1,18 +1,40 @@
|
|
|
1
1
|
import { isValidDate } from 'jet-validators';
|
|
2
2
|
import { traverseObject } from 'jet-validators/utils';
|
|
3
3
|
|
|
4
|
+
import { IReqPropErr } from '@src/routes/common';
|
|
5
|
+
import UserRepo from '@src/repos/UserRepo';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/******************************************************************************
|
|
9
|
+
Types
|
|
10
|
+
******************************************************************************/
|
|
11
|
+
|
|
12
|
+
export interface IValidationErr {
|
|
13
|
+
message: string;
|
|
14
|
+
parameters: IReqPropErr[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/******************************************************************************
|
|
19
|
+
Functions
|
|
20
|
+
******************************************************************************/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Delete all records for unit testing.
|
|
24
|
+
*/
|
|
25
|
+
export async function cleanDatabase(): Promise<void> {
|
|
26
|
+
await Promise.all([
|
|
27
|
+
UserRepo.deleteAllUsers(),
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
4
30
|
|
|
5
31
|
/**
|
|
6
|
-
*
|
|
7
|
-
* tests to pass we need to convert them back to date objects.
|
|
32
|
+
* Put things you need to do to modify the resp body object here.
|
|
8
33
|
*/
|
|
9
|
-
export function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return traverseObject((prop, value, parentObj) => {
|
|
14
|
-
if (toConvert.includes(prop) && isValidDate(value)) {
|
|
15
|
-
parentObj[prop] = new Date(value);
|
|
34
|
+
export function parseResBody(body: unknown) {
|
|
35
|
+
return traverseObject((key, val, parentObj) => {
|
|
36
|
+
if (key === 'created' && isValidDate(val)) {
|
|
37
|
+
parentObj[key] = new Date(val);
|
|
16
38
|
}
|
|
17
|
-
});
|
|
39
|
+
})(body);
|
|
18
40
|
}
|
|
@@ -1,45 +1,30 @@
|
|
|
1
|
-
import supertest
|
|
2
|
-
import TestAgent from 'supertest/lib/agent';
|
|
1
|
+
import supertest from 'supertest';
|
|
3
2
|
import insertUrlParams from 'inserturlparams';
|
|
4
3
|
import { parseJson } from 'jet-validators/utils';
|
|
5
|
-
import logger from 'jet-logger';
|
|
6
4
|
|
|
7
5
|
import app from '@src/server';
|
|
8
6
|
|
|
9
7
|
import UserRepo from '@src/repos/UserRepo';
|
|
10
|
-
import User
|
|
8
|
+
import User from '@src/models/User';
|
|
11
9
|
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
|
12
10
|
|
|
13
11
|
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
14
|
-
import {
|
|
12
|
+
import { ValidationErr } from '@src/common/route-errors';
|
|
15
13
|
|
|
16
14
|
import Paths from 'spec/support/Paths';
|
|
17
|
-
import {
|
|
18
|
-
import { TApiCb, TRes } from 'spec/types/misc';
|
|
15
|
+
import { cleanDatabase, IValidationErr, parseResBody } from 'spec/support';
|
|
19
16
|
|
|
20
17
|
|
|
21
18
|
/******************************************************************************
|
|
22
|
-
|
|
19
|
+
Variables
|
|
23
20
|
******************************************************************************/
|
|
24
21
|
|
|
25
22
|
// Dummy users for GET req
|
|
26
|
-
const
|
|
27
|
-
User.new({ name: 'Sean Maxwell', email: 'sean.maxwell@gmail.com' }),
|
|
28
|
-
User.new({ name: 'John Smith', email: 'john.smith@gmail.com' }),
|
|
29
|
-
User.new({ name: 'Gordan Freeman', email: 'gordan.freeman@gmail.com' }),
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
// Convert "created" prop back to Date object
|
|
33
|
-
const createdKeyToDate = convertValidDates('created');
|
|
34
|
-
|
|
35
|
-
// Setup wrap-callback function
|
|
36
|
-
const wrapCb = (cb: TApiCb) => (err: Error, res: TRes) => {
|
|
37
|
-
if (!!err) {
|
|
38
|
-
logger.err(err);
|
|
39
|
-
}
|
|
40
|
-
createdKeyToDate(res.body);
|
|
41
|
-
return cb(res);
|
|
42
|
-
};
|
|
23
|
+
const DB_USERS = [
|
|
24
|
+
User.new({ id: 1, name: 'Sean Maxwell', email: 'sean.maxwell@gmail.com' }),
|
|
25
|
+
User.new({ id: 2, name: 'John Smith', email: 'john.smith@gmail.com' }),
|
|
26
|
+
User.new({ id: 3, name: 'Gordan Freeman', email: 'gordan.freeman@gmail.com' }),
|
|
27
|
+
] as const;
|
|
43
28
|
|
|
44
29
|
|
|
45
30
|
/******************************************************************************
|
|
@@ -48,154 +33,138 @@ const wrapCb = (cb: TApiCb) => (err: Error, res: TRes) => {
|
|
|
48
33
|
|
|
49
34
|
describe('UserRouter', () => {
|
|
50
35
|
|
|
51
|
-
|
|
36
|
+
const agent = supertest.agent(app);
|
|
52
37
|
|
|
53
38
|
// Run before all tests
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
beforeEach(async () => {
|
|
40
|
+
await cleanDatabase();
|
|
41
|
+
await UserRepo.insertMult(DB_USERS);
|
|
57
42
|
});
|
|
58
43
|
|
|
59
44
|
// Get all users
|
|
60
45
|
describe(`"GET:${Paths.Users.Get}"`, () => {
|
|
61
46
|
|
|
62
|
-
// Setup API
|
|
63
|
-
const api = (cb: TApiCb) =>
|
|
64
|
-
agent
|
|
65
|
-
.get(Paths.Users.Get)
|
|
66
|
-
.end(wrapCb(cb));
|
|
67
|
-
|
|
68
47
|
// Success
|
|
69
48
|
it('should return a JSON object with all the users and a status code ' +
|
|
70
49
|
`of "${HttpStatusCodes.OK}" if the request was successful.`, done => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
50
|
+
agent
|
|
51
|
+
.get(Paths.Users.Get)
|
|
52
|
+
.end((_, res) => {
|
|
53
|
+
parseResBody(res.body);
|
|
54
|
+
expect(res.status).toBe(HttpStatusCodes.OK);
|
|
55
|
+
expect(res.body).toEqual({ users: DB_USERS });
|
|
56
|
+
done();
|
|
57
|
+
});
|
|
80
58
|
});
|
|
81
59
|
});
|
|
82
60
|
|
|
83
61
|
// Test add user
|
|
84
62
|
describe(`"POST:${Paths.Users.Add}"`, () => {
|
|
85
63
|
|
|
86
|
-
const DUMMY_USER = getDummyUsers()[0];
|
|
87
|
-
|
|
88
|
-
// Setup API
|
|
89
|
-
const callApi = (user: IUser | null, cb: TApiCb) =>
|
|
90
|
-
agent
|
|
91
|
-
.post(Paths.Users.Add)
|
|
92
|
-
.send({ user })
|
|
93
|
-
.end(wrapCb(cb));
|
|
94
|
-
|
|
95
64
|
// Test add user success
|
|
96
65
|
it(`should return a status code of "${HttpStatusCodes.CREATED}" if the ` +
|
|
97
66
|
'request was successful.', done => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
67
|
+
const user = User.new({ name: 'a', email: 'a@a.com' });
|
|
68
|
+
agent
|
|
69
|
+
.post(Paths.Users.Add)
|
|
70
|
+
.send({ user })
|
|
71
|
+
.end((_, res) => {
|
|
72
|
+
expect(res.status).toBe(HttpStatusCodes.CREATED);
|
|
73
|
+
done();
|
|
74
|
+
});
|
|
105
75
|
});
|
|
106
76
|
|
|
107
77
|
// Missing param
|
|
108
78
|
it('should return a JSON object with an error message of and a status ' +
|
|
109
79
|
`code of "${HttpStatusCodes.BAD_REQUEST}" if the user param was ` +
|
|
110
80
|
'missing.', done => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
81
|
+
agent
|
|
82
|
+
.post(Paths.Users.Add)
|
|
83
|
+
.send({ user: null })
|
|
84
|
+
.end((_, res) => {
|
|
85
|
+
expect(res.status).toBe(HttpStatusCodes.BAD_REQUEST);
|
|
86
|
+
const errorObj = parseJson<IValidationErr>(res.body.error);
|
|
87
|
+
expect(errorObj.message).toBe(ValidationErr.MSG);
|
|
88
|
+
expect(errorObj.parameters[0].prop).toBe('user');
|
|
89
|
+
done();
|
|
90
|
+
});
|
|
119
91
|
});
|
|
120
92
|
});
|
|
121
93
|
|
|
122
94
|
// Update users
|
|
123
95
|
describe(`"PUT:${Paths.Users.Update}"`, () => {
|
|
124
96
|
|
|
125
|
-
const DUMMY_USER = getDummyUsers()[0];
|
|
126
|
-
|
|
127
|
-
// Setup API
|
|
128
|
-
const callApi = (user: IUser | null, cb: TApiCb) =>
|
|
129
|
-
agent
|
|
130
|
-
.put(Paths.Users.Update)
|
|
131
|
-
.send({ user })
|
|
132
|
-
.end(wrapCb(cb));
|
|
133
|
-
|
|
134
97
|
// Success
|
|
135
98
|
it(`should return a status code of "${HttpStatusCodes.OK}" if the ` +
|
|
136
99
|
'request was successful.', done => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
100
|
+
const user = DB_USERS[0];
|
|
101
|
+
user.name = 'Bill';
|
|
102
|
+
agent
|
|
103
|
+
.put(Paths.Users.Update)
|
|
104
|
+
.send({ user })
|
|
105
|
+
.end((_, res) => {
|
|
106
|
+
expect(res.status).toBe(HttpStatusCodes.OK);
|
|
107
|
+
done();
|
|
108
|
+
});
|
|
143
109
|
});
|
|
144
110
|
|
|
145
111
|
// Param missing
|
|
146
112
|
it('should return a JSON object with an error message and a status code ' +
|
|
147
113
|
`of "${HttpStatusCodes.BAD_REQUEST}" if the user param was missing`,
|
|
148
114
|
done => {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
115
|
+
agent
|
|
116
|
+
.put(Paths.Users.Update)
|
|
117
|
+
.send({ user: null })
|
|
118
|
+
.end((_, res) => {
|
|
119
|
+
expect(res.status).toBe(HttpStatusCodes.BAD_REQUEST);
|
|
120
|
+
const errorObj = parseJson<IValidationErr>(res.body.error);
|
|
121
|
+
expect(errorObj.message).toBe(ValidationErr.MSG);
|
|
122
|
+
expect(errorObj.parameters[0].prop).toBe('user');
|
|
123
|
+
done();
|
|
124
|
+
});
|
|
156
125
|
});
|
|
157
126
|
|
|
158
127
|
// User not found
|
|
159
128
|
it('should return a JSON object with the error message of ' +
|
|
160
129
|
`"${USER_NOT_FOUND_ERR}" and a status code of ` +
|
|
161
130
|
`"${HttpStatusCodes.NOT_FOUND}" if the id was not found.`, done => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
131
|
+
const user = User.new({ id: 4, name: 'a', email: 'a@a.com' });
|
|
132
|
+
agent
|
|
133
|
+
.put(Paths.Users.Update)
|
|
134
|
+
.send({ user })
|
|
135
|
+
.end((_, res) => {
|
|
136
|
+
expect(res.status).toBe(HttpStatusCodes.NOT_FOUND);
|
|
137
|
+
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
138
|
+
done();
|
|
139
|
+
});
|
|
167
140
|
});
|
|
168
141
|
});
|
|
169
142
|
|
|
170
143
|
// Delete User
|
|
171
144
|
describe(`"DELETE:${Paths.Users.Delete}"`, () => {
|
|
172
145
|
|
|
173
|
-
// Call API
|
|
174
|
-
const callApi = (id: number, cb: TApiCb) =>
|
|
175
|
-
agent
|
|
176
|
-
.delete(insertUrlParams(Paths.Users.Delete, { id }))
|
|
177
|
-
.end(wrapCb(cb));
|
|
178
|
-
|
|
179
146
|
// Success
|
|
180
147
|
it(`should return a status code of "${HttpStatusCodes.OK}" if the ` +
|
|
181
148
|
'request was successful.', done => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
149
|
+
agent
|
|
150
|
+
.delete(insertUrlParams(Paths.Users.Delete, { id: 3 }))
|
|
151
|
+
.end((_, res) => {
|
|
152
|
+
expect(res.status).toBe(HttpStatusCodes.OK);
|
|
153
|
+
done();
|
|
154
|
+
});
|
|
188
155
|
});
|
|
189
156
|
|
|
190
157
|
// User not found
|
|
191
158
|
it('should return a JSON object with the error message of ' +
|
|
192
159
|
`"${USER_NOT_FOUND_ERR}" and a status code of ` +
|
|
193
160
|
`"${HttpStatusCodes.NOT_FOUND}" if the id was not found.`, done => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
161
|
+
agent
|
|
162
|
+
.delete(insertUrlParams(Paths.Users.Delete, { id: -1 }))
|
|
163
|
+
.end((_, res) => {
|
|
164
|
+
expect(res.status).toBe(HttpStatusCodes.NOT_FOUND);
|
|
165
|
+
expect(res.body.error).toBe(USER_NOT_FOUND_ERR);
|
|
166
|
+
done();
|
|
167
|
+
});
|
|
199
168
|
});
|
|
200
169
|
});
|
|
201
170
|
});
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
/******************************************************************************
|
|
5
|
-
Types
|
|
6
|
-
******************************************************************************/
|
|
7
|
-
|
|
8
|
-
export interface IValidationErrFormat {
|
|
9
|
-
error: string;
|
|
10
|
-
parameter: string;
|
|
11
|
-
value?: unknown;
|
|
12
|
-
'more-info'?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
4
|
/******************************************************************************
|
|
17
5
|
Classes
|
|
18
6
|
******************************************************************************/
|
|
@@ -33,17 +21,13 @@ export class RouteError extends Error {
|
|
|
33
21
|
* Validation in route layer errors.
|
|
34
22
|
*/
|
|
35
23
|
export class ValidationErr extends RouteError {
|
|
36
|
-
public static MSG = '
|
|
37
|
-
|
|
38
|
-
public constructor(
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!!moreInfo) {
|
|
45
|
-
msgObj['more-info'] = moreInfo;
|
|
46
|
-
}
|
|
47
|
-
super(HttpStatusCodes.BAD_REQUEST, JSON.stringify(msgObj));
|
|
24
|
+
public static MSG = 'One or more parameters were missing or invalid.';
|
|
25
|
+
|
|
26
|
+
public constructor(errObj: unknown) {
|
|
27
|
+
const msg = JSON.stringify({
|
|
28
|
+
message: ValidationErr.MSG,
|
|
29
|
+
parameters: errObj,
|
|
30
|
+
});
|
|
31
|
+
super(HttpStatusCodes.BAD_REQUEST, msg);
|
|
48
32
|
}
|
|
49
33
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logger from 'jet-logger';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import ENV from '@src/common/ENV';
|
|
4
4
|
import server from './server';
|
|
5
5
|
|
|
6
6
|
|
|
@@ -9,6 +9,6 @@ import server from './server';
|
|
|
9
9
|
******************************************************************************/
|
|
10
10
|
|
|
11
11
|
const SERVER_START_MSG = ('Express server started on port: ' +
|
|
12
|
-
|
|
12
|
+
ENV.Port.toString());
|
|
13
13
|
|
|
14
|
-
server.listen(
|
|
14
|
+
server.listen(ENV.Port, () => logger.info(SERVER_START_MSG));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import jsonfile from 'jsonfile';
|
|
2
2
|
|
|
3
|
+
import ENV from '@src/common/ENV';
|
|
4
|
+
import { NodeEnvs } from '@src/common/constants';
|
|
3
5
|
import { IUser } from '@src/models/User';
|
|
4
6
|
|
|
5
7
|
|
|
@@ -7,7 +9,11 @@ import { IUser } from '@src/models/User';
|
|
|
7
9
|
Variables
|
|
8
10
|
******************************************************************************/
|
|
9
11
|
|
|
10
|
-
const DB_FILE_NAME =
|
|
12
|
+
const DB_FILE_NAME = (
|
|
13
|
+
ENV.NodeEnv === NodeEnvs.Test
|
|
14
|
+
? 'database.test.json'
|
|
15
|
+
: 'database.json'
|
|
16
|
+
);
|
|
11
17
|
|
|
12
18
|
|
|
13
19
|
/******************************************************************************
|
|
@@ -83,6 +83,29 @@ async function delete_(id: number): Promise<void> {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
// **** Unit-Tests Only **** //
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Delete every user record.
|
|
90
|
+
*/
|
|
91
|
+
async function deleteAllUsers(): Promise<void> {
|
|
92
|
+
const db = await orm.openDb();
|
|
93
|
+
db.users = [];
|
|
94
|
+
return orm.saveDb(db);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Insert multiple users. Can't do multiple at once cause using a plain file
|
|
99
|
+
* for nmow.
|
|
100
|
+
*/
|
|
101
|
+
async function insertMult(users: IUser[] | readonly IUser[]): Promise<void> {
|
|
102
|
+
const db = await orm.openDb();
|
|
103
|
+
db.users = [ ...db.users, ...users];
|
|
104
|
+
return orm.saveDb(db);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
86
109
|
/******************************************************************************
|
|
87
110
|
Export default
|
|
88
111
|
******************************************************************************/
|
|
@@ -94,4 +117,6 @@ export default {
|
|
|
94
117
|
add,
|
|
95
118
|
update,
|
|
96
119
|
delete: delete_,
|
|
120
|
+
deleteAllUsers,
|
|
121
|
+
insertMult,
|
|
97
122
|
} as const;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"users":[{"id":1,"name":"Bill","created":"2025-02-10T05:36:18.360Z","email":"sean.maxwell@gmail.com"},{"id":2,"name":"John Smith","created":"2025-02-10T05:36:18.360Z","email":"john.smith@gmail.com"},{"id":3,"name":"Gordan Freeman","created":"2025-02-10T05:36:18.360Z","email":"gordan.freeman@gmail.com"}]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Response, Request } from 'express';
|
|
2
|
-
import { isObject } from 'jet-validators';
|
|
2
|
+
import { isObject, isString } from 'jet-validators';
|
|
3
3
|
import { parseObject, TSchema } from 'jet-validators/utils';
|
|
4
4
|
|
|
5
5
|
import { ValidationErr } from '@src/common/route-errors';
|
|
@@ -13,6 +13,12 @@ type TRecord = Record<string, unknown>;
|
|
|
13
13
|
export type IReq = Request<TRecord, void, TRecord, TRecord>;
|
|
14
14
|
export type IRes = Response<unknown, TRecord>;
|
|
15
15
|
|
|
16
|
+
export interface IReqPropErr {
|
|
17
|
+
prop: string;
|
|
18
|
+
value: unknown;
|
|
19
|
+
moreInfo?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
|
|
17
23
|
/******************************************************************************
|
|
18
24
|
Functions
|
|
@@ -22,27 +28,35 @@ export type IRes = Response<unknown, TRecord>;
|
|
|
22
28
|
* Parse a Request object property and throw a Validation error if it fails.
|
|
23
29
|
*/
|
|
24
30
|
export function parseReq<U extends TSchema>(schema: U) {
|
|
25
|
-
const parseFn = parseObject<U>(schema, _parseReqOnError);
|
|
26
31
|
return (arg: unknown) => {
|
|
32
|
+
// Don't alter original object
|
|
27
33
|
if (isObject(arg)) {
|
|
28
34
|
arg = { ...arg };
|
|
29
35
|
}
|
|
30
|
-
|
|
36
|
+
// Error callback
|
|
37
|
+
const errArr: IReqPropErr[] = [];
|
|
38
|
+
const errCb = (
|
|
39
|
+
prop = 'undefined',
|
|
40
|
+
value?: unknown,
|
|
41
|
+
caughtErr?: unknown,
|
|
42
|
+
) => {
|
|
43
|
+
const err: IReqPropErr = { prop, value };
|
|
44
|
+
if (caughtErr !== undefined) {
|
|
45
|
+
let moreInfo;
|
|
46
|
+
if (!isString(caughtErr)) {
|
|
47
|
+
moreInfo = JSON.stringify(caughtErr);
|
|
48
|
+
} else {
|
|
49
|
+
moreInfo = caughtErr;
|
|
50
|
+
}
|
|
51
|
+
err.moreInfo = moreInfo;
|
|
52
|
+
}
|
|
53
|
+
errArr.push(err);
|
|
54
|
+
};
|
|
55
|
+
// Return
|
|
56
|
+
const retVal = parseObject<U>(schema, errCb)(arg);
|
|
57
|
+
if (errArr.length > 0) {
|
|
58
|
+
throw new ValidationErr(errArr);
|
|
59
|
+
}
|
|
60
|
+
return retVal;
|
|
31
61
|
};
|
|
32
62
|
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Error handler for the request parse function above.
|
|
36
|
-
*/
|
|
37
|
-
function _parseReqOnError(
|
|
38
|
-
prop = 'undefined',
|
|
39
|
-
value?: unknown,
|
|
40
|
-
caughtErr?: unknown,
|
|
41
|
-
): void {
|
|
42
|
-
if (caughtErr !== undefined) {
|
|
43
|
-
const moreInfo = JSON.stringify(caughtErr);
|
|
44
|
-
throw new ValidationErr(prop, value, moreInfo);
|
|
45
|
-
} else {
|
|
46
|
-
throw new ValidationErr(prop, value);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -9,7 +9,7 @@ import 'express-async-errors';
|
|
|
9
9
|
import BaseRouter from '@src/routes';
|
|
10
10
|
|
|
11
11
|
import Paths from '@src/routes/common/Paths';
|
|
12
|
-
import
|
|
12
|
+
import ENV from '@src/common/ENV';
|
|
13
13
|
import HttpStatusCodes from '@src/common/HttpStatusCodes';
|
|
14
14
|
import { RouteError } from '@src/common/route-errors';
|
|
15
15
|
import { NodeEnvs } from '@src/common/constants';
|
|
@@ -29,12 +29,12 @@ app.use(express.json());
|
|
|
29
29
|
app.use(express.urlencoded({extended: true}));
|
|
30
30
|
|
|
31
31
|
// Show routes called in console during development
|
|
32
|
-
if (
|
|
32
|
+
if (ENV.NodeEnv === NodeEnvs.Dev.valueOf()) {
|
|
33
33
|
app.use(morgan('dev'));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
// Security
|
|
37
|
-
if (
|
|
37
|
+
if (ENV.NodeEnv === NodeEnvs.Production.valueOf()) {
|
|
38
38
|
app.use(helmet());
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -43,7 +43,7 @@ app.use(Paths.Base, BaseRouter);
|
|
|
43
43
|
|
|
44
44
|
// Add error handler
|
|
45
45
|
app.use((err: Error, _: Request, res: Response, next: NextFunction) => {
|
|
46
|
-
if (
|
|
46
|
+
if (ENV.NodeEnv !== NodeEnvs.Test.valueOf()) {
|
|
47
47
|
logger.err(err, true);
|
|
48
48
|
}
|
|
49
49
|
let status = HttpStatusCodes.BAD_REQUEST;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-generator-typescript",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.14",
|
|
4
4
|
"description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"express-generator-typescript": "node bin/cli.js",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Response } from 'supertest';
|
|
2
|
-
import { IUser } from '@src/models/User';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// Misc
|
|
6
|
-
export type TRes = Omit<Response, 'body'> & {
|
|
7
|
-
body: {
|
|
8
|
-
error?: string,
|
|
9
|
-
user?: IUser,
|
|
10
|
-
users?: IUser[],
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
export type TApiCb = (res: TRes) => void;
|
|
File without changes
|