nodester 0.1.5 → 0.2.1
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 +25 -61
- package/lib/application/index.js +185 -63
- package/lib/body/extract.js +15 -4
- package/lib/constants/Bounds.js +15 -0
- package/lib/constants/Clauses.js +13 -0
- package/lib/constants/ResponseFormats.js +2 -2
- package/lib/controllers/methods/index.js +7 -0
- package/lib/controllers/mixins/index.js +36 -36
- package/lib/database/connection.js +6 -0
- package/lib/database/migration.js +14 -4
- package/lib/facades/methods/index.js +10 -9
- package/lib/facades/mixins/index.js +67 -13
- package/lib/factories/responses/rest.js +25 -13
- package/lib/http/{request.js → request/index.js} +53 -75
- package/lib/http/request/utils.js +27 -0
- package/lib/http/response/headers.js +138 -0
- package/lib/http/response/index.js +248 -0
- package/lib/http/response/utils.js +38 -0
- package/lib/middlewares/SearchParams/index.js +25 -0
- package/lib/middlewares/cookies/index.js +44 -0
- package/lib/middlewares/etag/index.js +32 -15
- package/lib/middlewares/formidable/index.js +30 -25
- package/lib/middlewares/ql/sequelize/index.js +11 -2
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +10 -2
- package/lib/middlewares/render/index.js +62 -0
- package/lib/models/associate.js +25 -1
- package/lib/models/define.js +19 -15
- package/lib/models/mixins.js +7 -0
- package/lib/query/traverse.js +97 -63
- package/lib/router/handlers.util.js +1 -0
- package/lib/router/index.js +193 -98
- package/lib/router/markers.js +7 -0
- package/lib/router/route.js +5 -0
- package/lib/router/routes.util.js +12 -14
- package/lib/router/utils.js +7 -0
- package/lib/stacks/MarkersStack.js +41 -3
- package/lib/stacks/MiddlewaresStack.js +200 -0
- package/lib/structures/Enum.js +46 -0
- package/lib/structures/Filter.js +157 -0
- package/lib/structures/Params.js +55 -0
- package/lib/tools/sql.tool.js +7 -0
- package/lib/utils/objects.util.js +31 -24
- package/lib/utils/sanitizations.util.js +10 -4
- package/lib/validators/arguments.js +68 -0
- package/lib/validators/dates.js +7 -0
- package/lib/validators/numbers.js +7 -0
- package/package.json +11 -8
- package/tests/index.test.js +4 -4
- package/tests/nql.test.js +18 -1
- package/lib/database/utils.js +0 -19
- package/lib/enums/Enum.js +0 -16
- package/lib/filters/Filter.js +0 -109
- package/lib/http/response.js +0 -1074
- package/lib/http/utils.js +0 -254
- package/lib/params/Params.js +0 -37
- package/lib/policies/Role.js +0 -77
- package/lib/policies/RoleExtracting.js +0 -97
- package/lib/services/includes.service.js +0 -79
- package/lib/services/jwt.service.js +0 -147
- package/lib/stacks/MiddlewareStack.js +0 -159
package/Readme.md
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
# nodester
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/nodester)
|
|
4
|
+
[](https://www.npmjs.com/package/nodester)
|
|
5
|
+
|
|
6
|
+
> **nodester** is a modern and versatile Node.js framework designed to streamline the development of robust and scalable web applications.
|
|
7
|
+
|
|
8
|
+
**nodester Query Language (NQL):** The main reason of nodester's existence is the [nodester Query Language (NQL)](docs/Queries.md), an extension of standard REST API syntax, it lets you craft complex queries with hierarchical associations.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Install with NPM
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
npm install -S nodester
|
|
17
|
+
```
|
|
18
|
+
|
|
3
19
|
|
|
4
20
|
## Table of Contents
|
|
5
21
|
|
|
6
22
|
- [Usage](#usage)
|
|
7
23
|
- [Documentation](#documentation)
|
|
8
|
-
- [Extending App](#extending-application-functionality)
|
|
9
24
|
- [Philosophy](#philosophy)
|
|
10
25
|
- [License](#license)
|
|
11
26
|
- [Copyright](#copyright)
|
|
@@ -24,6 +39,7 @@ app.listen(8080, function() {
|
|
|
24
39
|
console.log('listening on port', app.port);
|
|
25
40
|
});
|
|
26
41
|
```
|
|
42
|
+
[How to setup "db" ➡️](docs/App.md#with-database)
|
|
27
43
|
|
|
28
44
|
|
|
29
45
|
## Documentation
|
|
@@ -33,10 +49,11 @@ app.listen(8080, function() {
|
|
|
33
49
|
[Core concepts documentation ➡️](docs/CoreConcepts.md)
|
|
34
50
|
|
|
35
51
|
|
|
36
|
-
### Queries & Querying - Nodester Query Language (
|
|
37
|
-
|
|
52
|
+
### Queries & Querying - Nodester Query Language (NQL)
|
|
53
|
+
The true strength of nodester lies in its query language. Serving as an extension of standard REST API syntax, it brings many aspects of SQL into REST requests, providing developers with a simple yet potent tool for expressive and efficient data querying.
|
|
38
54
|
|
|
39
|
-
|
|
55
|
+
Read more about it in the documentation:
|
|
56
|
+
[NQL documentaion ➡️](docs/Queries.md)
|
|
40
57
|
|
|
41
58
|
|
|
42
59
|
### Database
|
|
@@ -46,61 +63,8 @@ Supported drivers:
|
|
|
46
63
|
- PostgreSQL
|
|
47
64
|
|
|
48
65
|
|
|
49
|
-
###
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
#### Extending instance (safe way):
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
const serveStatic = require('serve-static');
|
|
56
|
-
|
|
57
|
-
const nodester = require('nodester');
|
|
58
|
-
|
|
59
|
-
const app = new nodester();
|
|
60
|
-
app.extend('static', serveStatic);
|
|
61
|
-
app.static(<path_to_static_directory/>);
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Short:
|
|
65
|
-
```js
|
|
66
|
-
const serveStatic = require('serve-static');
|
|
67
|
-
|
|
68
|
-
const nodester = require('nodester');
|
|
69
|
-
|
|
70
|
-
const app = new nodester();
|
|
71
|
-
app.extend('static', serveStatic)(<path_to_static_directory/>);
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Of course you might just do this:
|
|
75
|
-
```js
|
|
76
|
-
const serveStatic = require('serve-static');
|
|
77
|
-
|
|
78
|
-
const nodester = require('nodester');
|
|
79
|
-
|
|
80
|
-
const app = new nodester();
|
|
81
|
-
app.static = serveStatic;
|
|
82
|
-
````
|
|
83
|
-
But you'll never know if you did override any of the app's properties or did not.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
#### Extending class:
|
|
87
|
-
|
|
88
|
-
If you really want to override properties or use `nodester` as a boilerplate, you should extend default Application class:
|
|
89
|
-
|
|
90
|
-
```js
|
|
91
|
-
const NodesterApp = require('nodester');
|
|
92
|
-
|
|
93
|
-
class MyApp extends NodesterApp {
|
|
94
|
-
constructor(opts) {
|
|
95
|
-
super(opts)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Override everything you want here...
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Don't forget to expose.
|
|
102
|
-
module.exports = MyApp;
|
|
103
|
-
```
|
|
66
|
+
### Application
|
|
67
|
+
[Application documentation ➡️](docs/App.md)
|
|
104
68
|
|
|
105
69
|
|
|
106
70
|
## Philosophy
|
|
@@ -109,7 +73,7 @@ The Philosophy of `nodester` is to provide a developer with a tool that can buil
|
|
|
109
73
|
|
|
110
74
|
### Goal
|
|
111
75
|
|
|
112
|
-
The goal of `nodester` is to be a robust and flexible framework that makes development in iteratations easy,
|
|
76
|
+
The goal of `nodester` is to be a robust and flexible framework that makes development in iteratations easy, while laying the foundation for seamless scalability in the future.
|
|
113
77
|
|
|
114
78
|
|
|
115
79
|
## LICENSE
|
package/lib/application/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const Emitter = require('events');
|
|
9
|
-
const
|
|
9
|
+
const NodesterRouter = require('../router');
|
|
10
10
|
|
|
11
11
|
// Server:
|
|
12
12
|
const http = require('http');
|
|
@@ -14,45 +14,70 @@ const request = require('../http/request');
|
|
|
14
14
|
const response = require('../http/response');
|
|
15
15
|
|
|
16
16
|
// Middlewares:
|
|
17
|
-
const nodesterQL = require('../middlewares/ql/sequelize');
|
|
18
17
|
const bodyParser = require('body-parser');
|
|
18
|
+
const cookies = require('nodester/middlewares/cookies');
|
|
19
|
+
const nodesterQL = require('nodester/ql/sequelize');
|
|
20
|
+
|
|
21
|
+
// DB setup.
|
|
22
|
+
const { associateModels } = require('nodester/models/associate');
|
|
19
23
|
|
|
20
24
|
// Utils:
|
|
25
|
+
const Params = require('nodester/params');
|
|
21
26
|
const {
|
|
22
27
|
typeOf,
|
|
23
28
|
isConstructor
|
|
24
29
|
} = require('../utils/types.util');
|
|
25
|
-
const {
|
|
26
|
-
associateModels
|
|
27
|
-
} = require('../database/utils');
|
|
28
|
-
|
|
29
30
|
const { merge } = require('../utils/objects.util');
|
|
31
|
+
|
|
32
|
+
// Arguments validator.
|
|
33
|
+
const { ensure } = require('../validators/arguments');
|
|
34
|
+
|
|
35
|
+
// Console:
|
|
30
36
|
const consl = require('nodester/loggers/console');
|
|
31
37
|
const debug = require('debug')('nodester:application');
|
|
32
38
|
|
|
33
39
|
|
|
34
|
-
module.exports = class
|
|
40
|
+
module.exports = class NodesterApplication extends Emitter {
|
|
35
41
|
|
|
36
42
|
/**
|
|
37
|
-
* Initialize
|
|
43
|
+
* Initialize new `NodesterApplication`.
|
|
44
|
+
*
|
|
45
|
+
* @param {Object} [options]
|
|
46
|
+
* @param {String|Int} options.port
|
|
47
|
+
* @param {String} options.title
|
|
48
|
+
* @param {Boolean} options.finalhandlerEnabled
|
|
49
|
+
* @param {Object} options.middlewares
|
|
38
50
|
*
|
|
39
51
|
* @api public
|
|
40
52
|
*/
|
|
41
|
-
constructor(
|
|
53
|
+
constructor(options={}) {
|
|
42
54
|
super();
|
|
43
55
|
|
|
56
|
+
ensure(options, 'object', 'options');
|
|
57
|
+
|
|
58
|
+
// Unwrap options:
|
|
59
|
+
const {
|
|
60
|
+
port,
|
|
61
|
+
title,
|
|
62
|
+
finalhandlerEnabled,
|
|
63
|
+
middlewares
|
|
64
|
+
} = Params((options ?? {}), {
|
|
65
|
+
port: 8080,
|
|
66
|
+
title: null,
|
|
67
|
+
finalhandlerEnabled: true,
|
|
68
|
+
middlewares: {}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
|
|
44
72
|
// Fallback port.
|
|
45
|
-
this.port =
|
|
73
|
+
this.port = port;
|
|
46
74
|
|
|
47
|
-
//
|
|
48
|
-
this._router = new
|
|
75
|
+
// Router acts as a MiddlewareStack for the application.
|
|
76
|
+
this._router = new NodesterRouter({ finalhandlerEnabled });
|
|
49
77
|
|
|
50
78
|
// Reference to the database connection.
|
|
51
79
|
this._database = null;
|
|
52
80
|
|
|
53
|
-
// Reference to the Query parser.
|
|
54
|
-
this._queryParser = nodesterQL;
|
|
55
|
-
|
|
56
81
|
// Reference to the http(s) server,
|
|
57
82
|
this.server = null;
|
|
58
83
|
|
|
@@ -61,16 +86,67 @@ module.exports = class Application extends Emitter {
|
|
|
61
86
|
};
|
|
62
87
|
|
|
63
88
|
// Default middlewares:
|
|
64
|
-
const _withoutMiddlewares =
|
|
89
|
+
const _withoutMiddlewares = middlewares?.without ?? [];
|
|
90
|
+
|
|
91
|
+
// !WARNING: Order of middlewares is important:
|
|
92
|
+
|
|
93
|
+
if (_withoutMiddlewares.indexOf('nodester-ql') === -1) {
|
|
94
|
+
this.use(nodesterQL());
|
|
95
|
+
}
|
|
65
96
|
|
|
66
97
|
if (_withoutMiddlewares.indexOf('body-parser') === -1) {
|
|
67
98
|
this.use(bodyParser.json());
|
|
68
99
|
}
|
|
69
100
|
|
|
101
|
+
if (_withoutMiddlewares.indexOf('cookies') === -1) {
|
|
102
|
+
this.use(cookies());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// User can title their application:
|
|
106
|
+
if (!!title) {
|
|
107
|
+
// Rename CLI process.
|
|
108
|
+
process.title = title;
|
|
109
|
+
}
|
|
110
|
+
|
|
70
111
|
// Indicatorors.
|
|
71
|
-
this.
|
|
112
|
+
this._isListening = false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Getters:
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @return {MiddlewaresStack}
|
|
119
|
+
*
|
|
120
|
+
* @api public
|
|
121
|
+
*/
|
|
122
|
+
get middlewaresStack() {
|
|
123
|
+
return this._router.middlewaresStack;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Indicates whether user can add more middlewares or not.
|
|
128
|
+
*
|
|
129
|
+
* @return {Boolean} isLocked
|
|
130
|
+
*
|
|
131
|
+
* @api public
|
|
132
|
+
*/
|
|
133
|
+
get isLocked() {
|
|
134
|
+
return this._router.isLocked;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Indicates whether app is awaiting requests.
|
|
139
|
+
*
|
|
140
|
+
* @return {Boolean} isListening
|
|
141
|
+
*
|
|
142
|
+
* @api public
|
|
143
|
+
*/
|
|
144
|
+
get isListening() {
|
|
145
|
+
return this._isListening;
|
|
72
146
|
}
|
|
73
147
|
|
|
148
|
+
// Getters\
|
|
149
|
+
|
|
74
150
|
/*
|
|
75
151
|
* Expose the prototype that will get set on requests.
|
|
76
152
|
*
|
|
@@ -98,7 +174,7 @@ module.exports = class Application extends Emitter {
|
|
|
98
174
|
/*
|
|
99
175
|
* Sets (or overrides):
|
|
100
176
|
* - (database) main database of the application and tries to make connection
|
|
101
|
-
* - (router) default
|
|
177
|
+
* - (router) default NodesterRouter
|
|
102
178
|
*
|
|
103
179
|
* @api public
|
|
104
180
|
*/
|
|
@@ -114,34 +190,42 @@ module.exports = class Application extends Emitter {
|
|
|
114
190
|
* Sets (or overrides) main database of the application and tries to make connection.
|
|
115
191
|
*
|
|
116
192
|
* @param {Sequilize} sequilizeConnection
|
|
117
|
-
* @param {
|
|
193
|
+
* @param {Object} [options]
|
|
194
|
+
* @param {Boolean} options.associateModels
|
|
195
|
+
* @param {Boolean} options.crashOnError
|
|
196
|
+
*
|
|
118
197
|
* @return {sequilizeConnection.authenticate}
|
|
119
198
|
*
|
|
120
|
-
* @public
|
|
199
|
+
* @api public
|
|
121
200
|
*/
|
|
122
|
-
async setDatabase(sequilizeConnection,
|
|
201
|
+
async setDatabase(sequilizeConnection, options={}) {
|
|
123
202
|
try {
|
|
124
203
|
if (!sequilizeConnection) {
|
|
125
|
-
const err = new TypeError('Connection to database (Sequilize) can not be null or undefined.');
|
|
204
|
+
const err = new TypeError('Connection to a database (Sequilize) can not be null or undefined.');
|
|
126
205
|
throw err;
|
|
127
206
|
}
|
|
128
207
|
|
|
129
|
-
if (this.
|
|
130
|
-
const err = new Error(`Can't set database after application start.`);
|
|
208
|
+
if (this._isListening === true) {
|
|
209
|
+
const err = new Error(`Can't set database after an application start.`);
|
|
131
210
|
throw err;
|
|
132
211
|
}
|
|
133
212
|
|
|
134
213
|
// Test connection.
|
|
135
214
|
const result = await sequilizeConnection.authenticate();
|
|
136
|
-
|
|
137
|
-
|
|
215
|
+
|
|
216
|
+
if (options?.associateModels === true) {
|
|
217
|
+
// Associate models between each other.
|
|
218
|
+
await associateModels(sequilizeConnection);
|
|
219
|
+
}
|
|
220
|
+
|
|
138
221
|
// Set database.
|
|
139
222
|
this._database = sequilizeConnection;
|
|
140
223
|
|
|
141
224
|
return Promise.resolve(result);
|
|
142
225
|
}
|
|
143
226
|
catch(error) {
|
|
144
|
-
if (crashOnError === true) {
|
|
227
|
+
if (options?.crashOnError === true) {
|
|
228
|
+
Error.captureStackTrace(error, this.setDatabase);
|
|
145
229
|
throw error;
|
|
146
230
|
}
|
|
147
231
|
else {
|
|
@@ -156,9 +240,9 @@ module.exports = class Application extends Emitter {
|
|
|
156
240
|
/*
|
|
157
241
|
* Returns main database of the application.
|
|
158
242
|
*
|
|
159
|
-
* @return {SequilizeConnection}
|
|
243
|
+
* @return {SequilizeConnection} database
|
|
160
244
|
*
|
|
161
|
-
* @public
|
|
245
|
+
* @api public
|
|
162
246
|
*/
|
|
163
247
|
get database() {
|
|
164
248
|
return this._database;
|
|
@@ -168,7 +252,9 @@ module.exports = class Application extends Emitter {
|
|
|
168
252
|
/**
|
|
169
253
|
* Overrides default Router.
|
|
170
254
|
*
|
|
171
|
-
* @
|
|
255
|
+
* @param {NodesterRouter} newRouter
|
|
256
|
+
*
|
|
257
|
+
* @api public
|
|
172
258
|
*/
|
|
173
259
|
setRouter(newRouter) {
|
|
174
260
|
if (isConstructor(newRouter)) {
|
|
@@ -185,7 +271,7 @@ module.exports = class Application extends Emitter {
|
|
|
185
271
|
*
|
|
186
272
|
* @return {NodesterRouter}
|
|
187
273
|
*
|
|
188
|
-
* @public
|
|
274
|
+
* @api public
|
|
189
275
|
*/
|
|
190
276
|
get router() {
|
|
191
277
|
return this._router;
|
|
@@ -216,7 +302,15 @@ module.exports = class Application extends Emitter {
|
|
|
216
302
|
* @api public
|
|
217
303
|
*/
|
|
218
304
|
use(fnOrRouter) {
|
|
219
|
-
|
|
305
|
+
try {
|
|
306
|
+
ensure(fnOrRouter, 'object|function,required', 'fnOrRouter');
|
|
307
|
+
|
|
308
|
+
return this._router.use(fnOrRouter);
|
|
309
|
+
}
|
|
310
|
+
catch(error) {
|
|
311
|
+
Error.captureStackTrace(error, this.use);
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
220
314
|
}
|
|
221
315
|
|
|
222
316
|
|
|
@@ -227,7 +321,15 @@ module.exports = class Application extends Emitter {
|
|
|
227
321
|
* @api public
|
|
228
322
|
*/
|
|
229
323
|
only(markerName='') {
|
|
230
|
-
|
|
324
|
+
try {
|
|
325
|
+
ensure(markerName, 'string,required', 'markerName');
|
|
326
|
+
|
|
327
|
+
return this._router.only(markerName);
|
|
328
|
+
}
|
|
329
|
+
catch(error) {
|
|
330
|
+
Error.captureStackTrace(error, this.only);
|
|
331
|
+
throw error;
|
|
332
|
+
}
|
|
231
333
|
}
|
|
232
334
|
|
|
233
335
|
|
|
@@ -237,13 +339,16 @@ module.exports = class Application extends Emitter {
|
|
|
237
339
|
* @api public
|
|
238
340
|
*/
|
|
239
341
|
beforeStart(fn) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
throw err;
|
|
243
|
-
}
|
|
244
|
-
this._hooks.beforeStart = fn;
|
|
342
|
+
try {
|
|
343
|
+
ensure(fn, 'function,required', 'fn');
|
|
245
344
|
|
|
246
|
-
|
|
345
|
+
this._hooks.beforeStart = fn;
|
|
346
|
+
return this._hooks.beforeStart;
|
|
347
|
+
}
|
|
348
|
+
catch(error) {
|
|
349
|
+
Error.captureStackTrace(error, this.beforeStart);
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
247
352
|
}
|
|
248
353
|
|
|
249
354
|
|
|
@@ -260,19 +365,25 @@ module.exports = class Application extends Emitter {
|
|
|
260
365
|
await this._hooks.beforeStart.call(this);
|
|
261
366
|
}
|
|
262
367
|
catch(error) {
|
|
263
|
-
console.error('
|
|
368
|
+
console.error('NodesterApplication did not start due to error.');
|
|
264
369
|
consl.error(error);
|
|
370
|
+
|
|
371
|
+
Error.captureStackTrace(error, this.start);
|
|
265
372
|
return Promise.reject(error);
|
|
266
373
|
}
|
|
267
374
|
|
|
268
|
-
// Add query parser.
|
|
269
|
-
this._router.add.middleware(this._queryParser, 0);
|
|
270
375
|
|
|
271
|
-
|
|
272
|
-
|
|
376
|
+
try {
|
|
377
|
+
// Prepare router for processing.
|
|
378
|
+
this._router.lock();
|
|
273
379
|
|
|
274
|
-
|
|
275
|
-
|
|
380
|
+
const handler = this.handle.bind(this);
|
|
381
|
+
return handler;
|
|
382
|
+
}
|
|
383
|
+
catch(error) {
|
|
384
|
+
Error.captureStackTrace(error, this.start);
|
|
385
|
+
return Promise.reject(error);
|
|
386
|
+
}
|
|
276
387
|
}
|
|
277
388
|
|
|
278
389
|
|
|
@@ -281,26 +392,35 @@ module.exports = class Application extends Emitter {
|
|
|
281
392
|
*
|
|
282
393
|
* http.createServer(app.start()).listen(...)
|
|
283
394
|
*
|
|
284
|
-
* @param {
|
|
395
|
+
* @param {Integer|String} port
|
|
285
396
|
* @param {Mixed} ...
|
|
397
|
+
*
|
|
286
398
|
* @return {import('http').Server}
|
|
287
399
|
*
|
|
288
400
|
* @api public
|
|
289
401
|
*/
|
|
290
402
|
async listen(port, ...args) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this.port = _port;
|
|
403
|
+
try {
|
|
404
|
+
ensure(port, 'number|string,required', 'port');
|
|
294
405
|
|
|
295
|
-
|
|
406
|
+
// Remember port:
|
|
407
|
+
const _port = port ?? this.port;
|
|
408
|
+
this.port = _port;
|
|
296
409
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
this.server
|
|
300
|
-
|
|
410
|
+
debug(`listen on port ${ this.port }`);
|
|
411
|
+
|
|
412
|
+
if (!this.server) {
|
|
413
|
+
const handler = await this.start();
|
|
414
|
+
this.server = http.createServer(handler);
|
|
415
|
+
}
|
|
301
416
|
|
|
302
|
-
|
|
303
|
-
|
|
417
|
+
this._isListening = true;
|
|
418
|
+
return this.server.listen(_port, ...args);
|
|
419
|
+
}
|
|
420
|
+
catch(error) {
|
|
421
|
+
Error.captureStackTrace(error, this.listen);
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
304
424
|
}
|
|
305
425
|
|
|
306
426
|
|
|
@@ -324,15 +444,19 @@ module.exports = class Application extends Emitter {
|
|
|
324
444
|
|
|
325
445
|
/**
|
|
326
446
|
* Extends Application & makes sure, that "key" param is not present already.
|
|
447
|
+
*
|
|
327
448
|
* @param {String} key
|
|
328
449
|
* @param {Any} fnOrProperty
|
|
450
|
+
*
|
|
329
451
|
* @return {Any} fnOrProperty in Application
|
|
330
452
|
*
|
|
331
453
|
* @api public
|
|
332
454
|
*/
|
|
333
455
|
extend(key='', fnOrProperty) {
|
|
334
|
-
|
|
335
|
-
|
|
456
|
+
ensure(key, 'string,required', 'key');
|
|
457
|
+
ensure(fnOrProperty, 'required', 'fnOrProperty');
|
|
458
|
+
|
|
459
|
+
if (typeof this[key] !== 'undefined') {
|
|
336
460
|
const err = new TypeError(`Key ${ key } is already present in Application instance`);
|
|
337
461
|
throw err;
|
|
338
462
|
}
|
|
@@ -349,16 +473,14 @@ module.exports = class Application extends Emitter {
|
|
|
349
473
|
* @api public
|
|
350
474
|
*/
|
|
351
475
|
stop() {
|
|
352
|
-
if (this.
|
|
476
|
+
if (this._isListening !== true) {
|
|
353
477
|
console.warn('Nothing to stop. Server is not listening.');
|
|
354
478
|
return;
|
|
355
479
|
}
|
|
356
480
|
|
|
357
481
|
this.server.close();
|
|
358
|
-
this.
|
|
482
|
+
this._isListening = false;
|
|
359
483
|
|
|
360
484
|
this._router.unlock();
|
|
361
|
-
// Remove query parser.
|
|
362
|
-
this._router.remove.middleware(0);
|
|
363
485
|
}
|
|
364
486
|
}
|
package/lib/body/extract.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* /nodester
|
|
3
3
|
* MIT Licensed
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
'use strict';
|
|
6
7
|
|
|
7
8
|
const httpCodes = require('nodester/http/codes');
|
|
@@ -11,6 +12,16 @@ const Sanitizations = require('nodester/utils/sanitizations');
|
|
|
11
12
|
|
|
12
13
|
module.exports = extract;
|
|
13
14
|
|
|
15
|
+
/*
|
|
16
|
+
* Extracts data from the body, based on the rules in "filter".
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} body
|
|
19
|
+
* @param {NodesterFilter} filter
|
|
20
|
+
* @param {SequilizeModel} model
|
|
21
|
+
*
|
|
22
|
+
* @api public
|
|
23
|
+
* @return {Object} filteredBody
|
|
24
|
+
*/
|
|
14
25
|
function extract(body, filter=null, model) {
|
|
15
26
|
|
|
16
27
|
const sequelize = model.sequelize;
|
|
@@ -23,7 +34,7 @@ function extract(body, filter=null, model) {
|
|
|
23
34
|
|
|
24
35
|
|
|
25
36
|
// Result object.
|
|
26
|
-
const
|
|
37
|
+
const filteredBody = {};
|
|
27
38
|
|
|
28
39
|
for (const [key, value] of bodyEntries) {
|
|
29
40
|
const isInclude = availableIncludes.indexOf(key) > -1;
|
|
@@ -48,7 +59,7 @@ function extract(body, filter=null, model) {
|
|
|
48
59
|
}
|
|
49
60
|
const sanitized = Sanitizations[typeName](value, sanitizationOptions);
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
filteredBody[key] = sanitized;
|
|
52
63
|
|
|
53
64
|
continue;
|
|
54
65
|
}
|
|
@@ -64,7 +75,7 @@ function extract(body, filter=null, model) {
|
|
|
64
75
|
|
|
65
76
|
const association = model.associations[key];
|
|
66
77
|
|
|
67
|
-
|
|
78
|
+
filteredBody[key] = extract(value[0], filter.includes[key], association.target);
|
|
68
79
|
|
|
69
80
|
continue;
|
|
70
81
|
}
|
|
@@ -74,5 +85,5 @@ function extract(body, filter=null, model) {
|
|
|
74
85
|
throw err;
|
|
75
86
|
}
|
|
76
87
|
|
|
77
|
-
return
|
|
88
|
+
return filteredBody;
|
|
78
89
|
}
|