mockapi-msi 2.0.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,116 +1,319 @@
1
- # Dynamic mocking descriptive API (MockAPI)
2
-
3
- MockAPI help you buiding your app when requires connecting to a not yet built external API.
4
-
5
- MockAPI let you create fake responses with pre defined and dynamic data for defined endpoints.
6
-
7
- MockAPI also is intended to help you when, during testing phase, you cannot afford complex and expensive products (And you do not need them) that requires bulky configuration steps or depends directly on third party providers that you cannot control.
8
-
9
- ## Version 2.0.0 notes
10
-
11
- - Using NodeJS managers such as NVM causes configuration file not being picked from the execution/working folder.
12
- - New CORE class created and code moved from the main module.
13
- - Additional checking for the configuration file.
14
- - Folder file readear incorrect path contactenation fixed.
15
-
16
- ## Configuration file
17
-
18
- MockAPI can be used as it is. Without any additional coding activity. Just configure your endpoints and run ```main.js``` file.
19
-
20
- ### Configuring MockAPI
21
-
22
- Edit ```.mockapi-config``` to add your own endpoints, responses, parsers and data. Use standard YAML notation for this file.
23
-
24
- #### Main entry points
25
-
26
- **port** - Specify the HTTP port to be used by MockAPI to expose the defined endpoints.
27
-
28
- **enableCors** - Enable/Disable CORS for MockAPI.
29
-
30
- **externalModulesPath** - Optional configuration. Allows to specify a different path where the user custom handlers are located.
31
-
32
- **data** -
33
- Holds and describe the available data for all endpoints and responses.
34
-
35
- **endpoints** - Describe all available endpoints, its verbs and responses.
36
-
37
- **log** - Define MockAPI log level.
38
-
39
- **customHandlers** - Import a custom HTTP data handler. Use these custom handlers to manipulate the output of your responses for a particular endpoint.
40
-
41
- Within ```data``` entry, it is possible to define how the data must be handled. There are three built-in readers that comes with MockAPI.
42
-
43
- **csv** - Reads the defined data as CSV.
44
-
45
- **text** - Considers the data source as plain text.
46
-
47
- **folder** - Reads the files from the folder matching the incoming request name.
48
-
49
- #### Data definition
50
-
51
- ```yaml
52
- myRows:
53
- path: "./testdata/data.csv"
54
- reader: csv
55
- properties:
56
- - json
57
- - seq
58
- - 0
59
- ```
60
- The previous example defines a data source called ```myRows```, which will read the data from the defined ```path```, using the ```csv``` handler, parsing each row as ```json```, reading the values in a ```sequential``` order, starting from record ```0```.
61
-
62
- #### Endpoint definition
63
-
64
- ```yaml
65
- "/users":
66
- verb: get
67
- data: myRows
68
- responseStatus: 200
69
- responseContentType: "application/json"
70
- ```
71
- From the previous code snippet, we are defining an endpoint ```[MockAPI URL]:[PORT]/users```, which will accept ```get``` requests, answering always with ```200``` status code, using data from ```myRows``` data definition in ```JSON``` format.
72
-
73
- #### Custom handlers
74
-
75
- A custom handler let you manipulate the data as your will. First, define the handler as follows:
76
-
77
- ```yaml
78
- customHandlers:
79
- "custom":
80
- "myCustomHandler"
81
- ```
82
- The previous code defines a custom handler called ```custom``` and will use the script code called ```myCustomHandler```. The custom code must be placed inside of ```scripts``` folder and coded in JavaScript with NodeJS support.
83
-
84
- Your custom script must implement the following export format:
85
-
86
- ```javascript
87
- module.exports = {
88
- process: [Your function entry point]
89
- };
90
- ```
91
-
92
- #### Setting up the log level
93
-
94
- MockAPI logs information into the execution console. There are different levels of logs that can be used.
95
-
96
- ```yaml
97
- log: verbose
98
- #debug <- Useful for custom handlers
99
- #error <- Only exposes internal errors
100
- #verbose <- Logs debug, information and errors
101
- #none <- Turn off the logs
102
- ```
103
-
104
- ## MockAPI CLI
105
-
106
- MockAPI provides a small but helpful CLI. Type ```mockapi --help``` to get the available commands from the CLI once MockAPI is installed.
107
-
108
- #### The ```init``` command
109
-
110
- Once MockAPI is globally installed, you will need a configuration file with minimal information to be able of start mocking the API. The ```init``` command argument will lead you through different basic questions helping you to initialize this configuration file.
111
-
112
- ```powershell
113
- mockapi --init
114
- ```
115
-
116
- You can skip every question which will assign some default values to the configuration file. Later you could change these values using any text editor.
1
+ # Dynamic mocking descriptive API (MockAPI)
2
+
3
+ MockAPI help you buiding your app when requires connecting to a not yet built external API.
4
+
5
+ MockAPI let you create fake responses with pre defined and dynamic data for defined endpoints.
6
+
7
+ MockAPI also is intended to help you when, during testing phase, you cannot afford complex and expensive products (And you do not need them) that requires bulky configuration steps or depends directly on third party providers that you cannot control.
8
+
9
+ ## Version 2.4.0 notes
10
+
11
+ - **HTTPS support**: New `tls` configuration option with `cert` and `key` paths. When provided, MockAPI starts an HTTPS server instead of HTTP.
12
+ - **Unit tests**: Test suite added using Node.js built-in test runner. Tests cover CSV parsing, URL parsing, path matching, HttpException, and Core HTTP server behavior. Run with `npm test`.
13
+
14
+ ## Version 2.3.0 notes
15
+
16
+ - **CORS fine-tuning**: `enableCors` now accepts an object to configure specific origins, methods, and headers. Preflight (OPTIONS) requests are handled automatically. Boolean `true` is still supported for allow-all behavior.
17
+ - **Graceful shutdown**: The server now handles `SIGTERM` and `SIGINT` signals, cleanly closing the HTTP server and config watcher before exiting.
18
+ - **Static file serving**: New `staticPath` configuration option serves files from a local directory. Requests that don't match any endpoint will attempt to serve a static file before returning 404.
19
+
20
+ ## Version 2.2.0 notes
21
+
22
+ - **Path parameters**: Endpoints now support path parameters using `:param` syntax (e.g., `/users/:id`). Extracted parameters are available in custom handlers via `requestInformation.params`.
23
+ - **Query parameters**: Query string parameters are now parsed and available in custom handlers via `requestInformation.query`.
24
+ - **Response delay**: Endpoints can now simulate slow APIs with a `delay` property (in milliseconds).
25
+ - **Hot-reload**: The configuration file is watched for changes. Endpoints and data sources are automatically reloaded without restarting the server.
26
+
27
+ ## Version 2.1.0 notes
28
+
29
+ - Codebase modernized to ES6 classes (`HttpException`, `Log`, `CSV`).
30
+ - CSV parser rewritten with RFC 4180 compliant state machine. Correctly handles commas inside quoted fields, escaped quotes, and mixed line endings (`\r\n`, `\n`, `\r`).
31
+ - Fixed bug in `urlParser` (`searchParamss` typo).
32
+ - Fixed bug in `moduleProxy.execute()` referencing a variable outside its scope.
33
+ - Fixed invalid top-level `return` statements in `main.js`.
34
+ - Docker image updated from Node 12 (EOL) to Node 20 LTS; switched to `npm ci --omit=dev`.
35
+ - Removed deprecated `version` key from Docker Compose files.
36
+ - `package.json` updated with `files`, `keywords`, and engine requirement bumped to `>=18`.
37
+ - Custom handler example (`myCustomHandler.js`) modernized with JSDoc and meaningful sample logic.
38
+ - ASCII art banner displayed on application startup.
39
+
40
+ ## Version 2.0.1 notes
41
+
42
+ - A bug related to custom handlers was detected and fixed.
43
+
44
+ ## Version 2.0.0 notes
45
+
46
+ - Using NodeJS managers such as NVM causes configuration file not being picked from the execution/working folder.
47
+ - New CORE class created and code moved from the main module.
48
+ - Additional checking for the configuration file.
49
+ - Folder file readear incorrect path contactenation fixed.
50
+
51
+ ## Configuration file
52
+
53
+ MockAPI can be used as it is. Without any additional coding activity. Just configure your endpoints and run ```main.js``` file.
54
+
55
+ ### Configuring MockAPI
56
+
57
+ Edit ```.mockapi-config``` to add your own endpoints, responses, parsers and data. Use standard YAML notation for this file.
58
+
59
+ #### Main entry points
60
+
61
+ **port** - Specify the HTTP port to be used by MockAPI to expose the defined endpoints.
62
+
63
+ **enableCors** - Configure CORS for MockAPI. Accepts ```true``` for allow-all behavior, or an object for fine-grained control.
64
+
65
+ **externalModulesPath** - Optional configuration. Allows to specify a different path where the user custom handlers are located.
66
+
67
+ **staticPath** - Optional configuration. Path to a local directory to serve static files from. Requests that don't match any endpoint will fall back to static file serving.
68
+
69
+ **data** -
70
+ Holds and describe the available data for all endpoints and responses.
71
+
72
+ **endpoints** - Describe all available endpoints, its verbs and responses.
73
+
74
+ **log** - Define MockAPI log level.
75
+
76
+ **customHandlers** - Import a custom HTTP data handler. Use these custom handlers to manipulate the output of your responses for a particular endpoint.
77
+
78
+ Within ```data``` entry, it is possible to define how the data must be handled. There are three built-in readers that comes with MockAPI.
79
+
80
+ **csv** - Reads the defined data as CSV.
81
+
82
+ **text** - Considers the data source as plain text.
83
+
84
+ **folder** - Reads the files from the folder matching the incoming request name.
85
+
86
+ #### Data definition
87
+
88
+ ```yaml
89
+ myRows:
90
+ path: "./testdata/data.csv"
91
+ reader: csv
92
+ properties:
93
+ - json
94
+ - seq
95
+ - 0
96
+ ```
97
+ The previous example defines a data source called ```myRows```, which will read the data from the defined ```path```, using the ```csv``` handler, parsing each row as ```json```, reading the values in a ```sequential``` order, starting from record ```0```.
98
+
99
+ #### Endpoint definition
100
+
101
+ ```yaml
102
+ "/users":
103
+ verb: get
104
+ data: myRows
105
+ responseStatus: 200
106
+ responseContentType: "application/json"
107
+ ```
108
+ From the previous code snippet, we are defining an endpoint ```[MockAPI URL]:[PORT]/users```, which will accept ```get``` requests, answering always with ```200``` status code, using data from ```myRows``` data definition in ```JSON``` format.
109
+
110
+ #### Path parameters
111
+
112
+ Endpoints support path parameters using the ```:param``` syntax. Parameters are extracted from the URL and made available to custom handlers.
113
+
114
+ ```yaml
115
+ "/users/:id":
116
+ verb: get
117
+ data: myRows
118
+ responseStatus: 200
119
+ responseContentType: "application/json"
120
+ ```
121
+
122
+ A request to ```/users/42``` will match this endpoint and extract ```{ id: "42" }``` as path parameters. Multiple path parameters are supported (e.g., ```/users/:userId/orders/:orderId```).
123
+
124
+ A custom handler can then use these parameters:
125
+
126
+ ```javascript
127
+ const process = (requestInformation, data) => {
128
+ const userId = requestInformation.params.id;
129
+ // requestInformation.params contains all extracted path parameters
130
+ // requestInformation.query contains all query string parameters
131
+ return JSON.stringify({ userId, data: JSON.parse(data) });
132
+ };
133
+
134
+ module.exports = { process };
135
+ ```
136
+
137
+ Combining path and query parameters, a request to ```/users/42?fields=name,email``` would provide:
138
+
139
+ ```javascript
140
+ requestInformation.params // { id: "42" }
141
+ requestInformation.query // { fields: "name,email" }
142
+ ```
143
+
144
+ #### Query parameters
145
+
146
+ Query string parameters are automatically parsed from the request URL. For example, a request to ```/users?role=admin&active=true``` will make ```{ role: "admin", active: "true" }``` available in custom handlers via ```requestInformation.query```.
147
+
148
+ #### Response delay
149
+
150
+ Simulate slow API responses by adding a ```delay``` property (in milliseconds) to any endpoint:
151
+
152
+ ```yaml
153
+ "/users":
154
+ verb: get
155
+ data: myRows
156
+ delay: 2000
157
+ responseStatus: 200
158
+ responseContentType: "application/json"
159
+ ```
160
+
161
+ The previous example will wait ```2000ms``` before sending the response, which is useful for testing loading states, spinners and timeout handling.
162
+
163
+ #### Hot-reload
164
+
165
+ MockAPI watches the ```.mockapi-config``` file for changes. When the file is saved, endpoints and data sources are automatically reloaded without restarting the server. This allows you to add, remove, or modify endpoints while the server is running.
166
+
167
+ #### CORS configuration
168
+
169
+ CORS can be configured in three ways:
170
+
171
+ **Disabled** (default):
172
+ ```yaml
173
+ enableCors: false
174
+ ```
175
+
176
+ **Allow all** (same as previous versions):
177
+ ```yaml
178
+ enableCors: true
179
+ ```
180
+
181
+ **Fine-grained control** — specify allowed origins, methods, and headers:
182
+ ```yaml
183
+ enableCors:
184
+ origins:
185
+ - "http://localhost:3000"
186
+ - "https://myapp.example.com"
187
+ methods:
188
+ - GET
189
+ - POST
190
+ - PUT
191
+ headers:
192
+ - Content-Type
193
+ - Authorization
194
+ ```
195
+
196
+ When using fine-grained CORS, MockAPI automatically handles ```OPTIONS``` preflight requests. If the request origin is not in the allowed list, CORS headers are not set.
197
+
198
+ #### Static file serving
199
+
200
+ MockAPI can serve static files from a local directory. Add the ```staticPath``` property to your configuration:
201
+
202
+ ```yaml
203
+ staticPath: "./public"
204
+ ```
205
+
206
+ When a request does not match any configured endpoint, MockAPI will attempt to serve a matching file from the specified directory. The file's MIME type is determined automatically from its extension. Supported types include HTML, CSS, JavaScript, JSON, PNG, JPG, GIF, SVG, PDF, and more.
207
+
208
+ For example, with ```staticPath: "./public"```, a request to ```/images/logo.png``` will serve the file at ```./public/images/logo.png```.
209
+
210
+ #### HTTPS
211
+
212
+ MockAPI supports HTTPS. Add a ```tls``` section to your configuration with the paths to your certificate and private key files:
213
+
214
+ ```yaml
215
+ tls:
216
+ cert: "./certs/server.crt"
217
+ key: "./certs/server.key"
218
+ ```
219
+
220
+ When TLS is configured, MockAPI starts an HTTPS server instead of HTTP. If the certificate files cannot be read, MockAPI falls back to HTTP and logs an error.
221
+
222
+ To generate a self-signed certificate for local development:
223
+
224
+ ```bash
225
+ openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/CN=localhost"
226
+ ```
227
+
228
+ #### Custom handlers
229
+
230
+ A custom handler let you manipulate the data as your will. First, define the handler as follows:
231
+
232
+ ```yaml
233
+ customHandlers:
234
+ "custom":
235
+ "myCustomHandler"
236
+ ```
237
+ The previous code defines a custom handler called ```custom``` and will use the script code called ```myCustomHandler```. The custom code must be placed inside of ```scripts``` folder and coded in JavaScript with NodeJS support.
238
+
239
+ Your custom script must implement the following export format:
240
+
241
+ ```javascript
242
+ module.exports = {
243
+ process: [Your function entry point]
244
+ };
245
+ ```
246
+
247
+ #### Setting up the log level
248
+
249
+ MockAPI logs information into the execution console. There are different levels of logs that can be used.
250
+
251
+ ```yaml
252
+ log: verbose
253
+ #debug <- Useful for custom handlers
254
+ #error <- Only exposes internal errors
255
+ #verbose <- Logs debug, information and errors
256
+ #none <- Turn off the logs
257
+ ```
258
+
259
+ ## MockAPI CLI
260
+
261
+ MockAPI provides a small but helpful CLI. Type ```mockapi --help``` to get the available commands from the CLI once MockAPI is installed.
262
+
263
+ #### The ```init``` command
264
+
265
+ Once MockAPI is globally installed, you will need a configuration file with minimal information to be able of start mocking the API. The ```init``` command argument will lead you through different basic questions helping you to initialize this configuration file.
266
+
267
+ ```powershell
268
+ mockapi --init
269
+ ```
270
+
271
+ You can skip every question which will assign some default values to the configuration file. Later you could change these values using any text editor.
272
+
273
+ ## Running MockAPI with Docker
274
+
275
+ MockAPI includes Docker support for running the application in a containerized environment.
276
+
277
+ ### Building the Docker image
278
+
279
+ ```bash
280
+ docker build -t mockapi .
281
+ ```
282
+
283
+ ### Running with Docker
284
+
285
+ ```bash
286
+ docker run -p 3001:8001 -v $(pwd)/.mockapi-config:/usr/src/app/.mockapi-config mockapi
287
+ ```
288
+
289
+ This maps port `3001` on your host to port `8001` inside the container and mounts your local configuration file into the container. Adjust the port mapping to match the `port` value in your `.mockapi-config` file.
290
+
291
+ ### Running with Docker Compose
292
+
293
+ #### Production mode
294
+
295
+ ```bash
296
+ docker compose up
297
+ ```
298
+
299
+ This builds and starts MockAPI using the `docker-compose.yml` file, exposing the API on port `3001`.
300
+
301
+ #### Debug mode
302
+
303
+ ```bash
304
+ docker compose -f docker-compose.debug.yml up
305
+ ```
306
+
307
+ This starts MockAPI with the Node.js inspector enabled on port `9229`, allowing you to attach a debugger. The API is available on port `3000`.
308
+
309
+ ### Mounting custom data and handlers
310
+
311
+ To use your own data files and custom handlers with Docker, mount them as volumes:
312
+
313
+ ```bash
314
+ docker run -p 3001:8001 \
315
+ -v $(pwd)/.mockapi-config:/usr/src/app/.mockapi-config \
316
+ -v $(pwd)/testdata:/usr/src/app/testdata \
317
+ -v $(pwd)/apiHandlers:/usr/src/app/apiHandlers \
318
+ mockapi
319
+ ```
@@ -1,9 +1,26 @@
1
- const action = function (requestInformation, data) {
2
- console.log(data);
3
- console.log(requestInformation);
4
- return JSON.stringify("Hello from custom module");
5
- };
6
-
7
- module.exports = {
8
- process: action
9
- };
1
+ /**
2
+ * Example custom handler for MockAPI.
3
+ *
4
+ * Custom handlers let you manipulate the response for an endpoint.
5
+ * When an endpoint uses a handler, this module processes the data
6
+ * instead of returning it directly.
7
+ *
8
+ * @param {Object} requestInformation - Incoming request details.
9
+ * @param {string} requestInformation.method - HTTP method (get, post, etc.).
10
+ * @param {string} requestInformation.url - Matched endpoint URL.
11
+ * @param {string} requestInformation.body - Raw request body.
12
+ * @param {string} data - Pre-processed data from the configured data reader.
13
+ * @returns {string} The response body to send back to the client.
14
+ */
15
+ const process = (requestInformation, data) => {
16
+ // Example: wrap the data in an envelope with request metadata
17
+ const response = {
18
+ endpoint: requestInformation.url,
19
+ method: requestInformation.method,
20
+ payload: data ? JSON.parse(data) : null
21
+ };
22
+
23
+ return JSON.stringify(response);
24
+ };
25
+
26
+ module.exports = { process };
package/main.js CHANGED
@@ -1,53 +1,87 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- const LOG = require('./modules/log');
6
- const YAML = require('yaml');
7
- const constants = require('./modules/constants');
8
- const readers = require('./modules/readers');
9
- const ModuleProxy = require('./modules/moduleProxy');
10
- const CLI = require('./modules/cli');
11
- const CORE = require('./modules/core');
12
-
13
- const rootPath = process.cwd();
14
- const configFilePath = `${rootPath}/${constants.CONFIG_FILE_NAME}`;
15
-
16
- const cli = new CLI(configFilePath);
17
-
18
- if (cli.hasCommands()) {
19
- cli.executeCommandLine();
20
- return false;
21
- }
22
-
23
- if (!readers.file_exists(configFilePath)) {
24
- console.log(`Configuration file not found. Please run ${constants.COLOR.fgGreen}--init${constants.COLOR.reset} using the CLI.`);
25
- return false;
26
- }
27
-
28
- const configFile = readers.text_reader(configFilePath);
29
- const parsedConfiguration = YAML.parse(configFile());
30
-
31
- if (parsedConfiguration.port === undefined) throw new Error("port property is required");
32
-
33
- const logLevel = parsedConfiguration.log || constants.LOG_LEVELS.ALL;
34
- const log = new LOG(logLevel);
35
- const moduleProxy = new ModuleProxy(parsedConfiguration.externalModulesPath || constants.EXTERNAL_MODULES_PATH, log);
36
-
37
- if (parsedConfiguration.customHandlers !== undefined) {
38
- moduleProxy.load(parsedConfiguration.customHandlers);
39
- }
40
-
41
- log.message(``);
42
- log.message(`Mock API configuration:`);
43
- log.message(` PORT: ${constants.COLOR.fgGreen}${parsedConfiguration.port}${constants.COLOR.reset}`);
44
- log.message(` CORS enabled: ${parsedConfiguration.enableCors ? constants.COLOR.fgGreen : constants.COLOR.fgRed}${parsedConfiguration.enableCors}${constants.COLOR.reset}`);
45
- log.message(``);
46
-
47
- log.message(`> Mock API attempting to use port: ${constants.COLOR.fgRed}${parsedConfiguration.port}${constants.COLOR.reset}`)
48
-
49
- const core = new CORE(log, parsedConfiguration, moduleProxy);
50
- core.run();
51
-
52
- log.message(`> Mock API listening on port: ${constants.COLOR.fgGreen}${parsedConfiguration.port}${constants.COLOR.reset}`)
53
- log.message(``);
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const LOG = require('./modules/log');
6
+ const YAML = require('yaml');
7
+ const constants = require('./modules/constants');
8
+ const readers = require('./modules/readers');
9
+ const ModuleProxy = require('./modules/moduleProxy');
10
+ const CLI = require('./modules/cli');
11
+ const CORE = require('./modules/core');
12
+ const banner = require('./modules/banner');
13
+ const ConfigWatcher = require('./modules/configWatcher');
14
+
15
+ const rootPath = process.cwd();
16
+ const configFilePath = `${rootPath}/${constants.CONFIG_FILE_NAME}`;
17
+
18
+ const cli = new CLI(configFilePath);
19
+
20
+ if (cli.hasCommands()) {
21
+ cli.executeCommandLine();
22
+ process.exit(0);
23
+ }
24
+
25
+ if (!readers.file_exists(configFilePath)) {
26
+ console.log(`Configuration file not found. Please run ${constants.COLOR.fgGreen}--init${constants.COLOR.reset} using the CLI.`);
27
+ process.exit(1);
28
+ }
29
+
30
+ const configFile = readers.text_reader(configFilePath);
31
+ const parsedConfiguration = YAML.parse(configFile());
32
+
33
+ if (parsedConfiguration.port === undefined) throw new Error("port property is required");
34
+
35
+ const logLevel = parsedConfiguration.log || constants.LOG_LEVELS.ALL;
36
+ const log = new LOG(logLevel);
37
+ const moduleProxy = new ModuleProxy(`file://${rootPath}/${(parsedConfiguration.externalModulesPath || constants.EXTERNAL_MODULES_PATH)}`, log);
38
+
39
+ if (parsedConfiguration.customHandlers !== undefined) {
40
+ moduleProxy.load(parsedConfiguration.customHandlers);
41
+ }
42
+
43
+ log.message(``);
44
+ banner.display();
45
+ log.message(`Mock API configuration:`);
46
+ log.message(` PORT: ${constants.COLOR.fgGreen}${parsedConfiguration.port}${constants.COLOR.reset}`);
47
+ log.message(` CORS enabled: ${parsedConfiguration.enableCors ? constants.COLOR.fgGreen : constants.COLOR.fgRed}${!!parsedConfiguration.enableCors}${constants.COLOR.reset}`);
48
+ log.message(` HTTPS: ${parsedConfiguration.tls ? constants.COLOR.fgGreen + 'enabled' : constants.COLOR.fgRed + 'disabled'}${constants.COLOR.reset}`);
49
+ if (parsedConfiguration.staticPath) {
50
+ log.message(` Static files: ${constants.COLOR.fgGreen}${parsedConfiguration.staticPath}${constants.COLOR.reset}`);
51
+ }
52
+ log.message(``);
53
+
54
+ const protocol = parsedConfiguration.tls ? 'https' : 'http';
55
+
56
+ log.message(`> Mock API attempting to use port: ${constants.COLOR.fgRed}${parsedConfiguration.port}${constants.COLOR.reset}`)
57
+
58
+ const core = new CORE(log, parsedConfiguration, moduleProxy);
59
+ core.run();
60
+
61
+ log.message(`> Mock API listening on ${constants.COLOR.fgGreen}${protocol}://localhost:${parsedConfiguration.port}${constants.COLOR.reset}`);
62
+
63
+ const watcher = new ConfigWatcher(configFilePath, log, (newConfig) => {
64
+ core.reload(newConfig);
65
+ log.message(`> Configuration reloaded. Endpoints updated.`);
66
+ });
67
+ watcher.watch();
68
+
69
+ log.message(`> Hot-reload enabled. Watching ${constants.COLOR.fgYellow}${constants.CONFIG_FILE_NAME}${constants.COLOR.reset} for changes.`);
70
+ log.message(``);
71
+
72
+ let isShuttingDown = false;
73
+
74
+ const shutdown = (signal) => {
75
+ if (isShuttingDown) return;
76
+ isShuttingDown = true;
77
+
78
+ log.message(`\n> ${signal} received. Shutting down gracefully...`);
79
+ watcher.stop();
80
+ core.stop(() => {
81
+ log.message(`> Mock API stopped.`);
82
+ process.exit(0);
83
+ });
84
+ };
85
+
86
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
87
+ process.on('SIGINT', () => shutdown('SIGINT'));
@@ -1,31 +1,9 @@
1
- function HttpException(httpStatusCode, message) {
2
- var instance = new Error(message);
3
-
4
- instance.name = 'HttpException';
5
- instance.httpStatusCode = httpStatusCode;
6
-
7
- Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
8
-
9
- if (Error.captureStackTrace) {
10
- Error.captureStackTrace(instance, HttpException);
11
- }
12
-
13
- return instance;
14
- }
15
-
16
- HttpException.prototype = Object.create(Error.prototype, {
17
- constructor: {
18
- value: Error,
19
- enumerable: false,
20
- writable: true,
21
- configurable: true
22
- }
23
- });
24
-
25
- if (Object.setPrototypeOf){
26
- Object.setPrototypeOf(HttpException, Error);
27
- } else {
28
- HttpException.__proto__ = Error;
29
- }
30
-
1
+ class HttpException extends Error {
2
+ constructor(httpStatusCode, message) {
3
+ super(message);
4
+ this.name = 'HttpException';
5
+ this.httpStatusCode = httpStatusCode;
6
+ }
7
+ }
8
+
31
9
  module.exports = HttpException;