mockapi-msi 2.0.1 → 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/modules/log.js CHANGED
@@ -1,39 +1,43 @@
1
- const constants = require("./constants");
2
-
3
- const Log = function(logLevel) {
4
- this._logLevel = logLevel || "verbose";
5
- };
6
-
7
- Log.prototype._write = function (message) {
8
- const date = (new Date()).toString();
9
-
10
- console.log(`${date} ${message}`);
11
- };
12
-
13
- Log.prototype.debug = function (message) {
14
- if (this._logLevel === constants.LOG_LEVELS.DEBUG || this._logLevel === constants.LOG_LEVELS.VERBOSE) {
15
- this._write(`${constants.COLOR.fgYellow}[DEBUG]${constants.COLOR.reset} - ${message}`);
16
- }
17
- };
18
-
19
- Log.prototype.error = function (message) {
20
- if (this._logLevel === constants.LOG_LEVELS.ERROR || this._logLevel === constants.LOG_LEVELS.VERBOSE) {
21
- this._write(`${constants.COLOR.fgRed}[ERROR]${constants.COLOR.reset} - ${message}`);
22
- }
23
- };
24
-
25
- Log.prototype.info = function (message) {
26
- if (this._logLevel === constants.LOG_LEVELS.VERBOSE) {
27
- this._write(`${constants.COLOR.fgYellow}[INFO]${constants.COLOR.reset} - ${message}`);
28
- }
29
- };
30
-
31
- Log.prototype.detail = function (message) {
32
- if (this._logLevel === constants.LOG_LEVELS.VERBOSE) {
33
- this._write(`${message}`);
34
- }
35
- };
36
-
37
- Log.prototype.message = (message) => console.log(message);
38
-
1
+ const constants = require("./constants");
2
+
3
+ class Log {
4
+
5
+ constructor(logLevel) {
6
+ this._logLevel = logLevel || "verbose";
7
+ }
8
+
9
+ _write(message) {
10
+ const date = (new Date()).toISOString();
11
+ console.log(`${date} ${message}`);
12
+ }
13
+
14
+ debug(message) {
15
+ if (this._logLevel === constants.LOG_LEVELS.DEBUG || this._logLevel === constants.LOG_LEVELS.VERBOSE) {
16
+ this._write(`${constants.COLOR.fgYellow}[DEBUG]${constants.COLOR.reset} - ${message}`);
17
+ }
18
+ }
19
+
20
+ error(message) {
21
+ if (this._logLevel === constants.LOG_LEVELS.ERROR || this._logLevel === constants.LOG_LEVELS.VERBOSE) {
22
+ this._write(`${constants.COLOR.fgRed}[ERROR]${constants.COLOR.reset} - ${message}`);
23
+ }
24
+ }
25
+
26
+ info(message) {
27
+ if (this._logLevel === constants.LOG_LEVELS.VERBOSE) {
28
+ this._write(`${constants.COLOR.fgYellow}[INFO]${constants.COLOR.reset} - ${message}`);
29
+ }
30
+ }
31
+
32
+ detail(message) {
33
+ if (this._logLevel === constants.LOG_LEVELS.VERBOSE) {
34
+ this._write(`${message}`);
35
+ }
36
+ }
37
+
38
+ message(message) {
39
+ console.log(message);
40
+ }
41
+ }
42
+
39
43
  module.exports = Log;
@@ -1,55 +1,52 @@
1
- const constants = require("./constants");
2
- const HttpException = require('./HttpException');
3
-
4
- class Proxy {
5
-
6
- _externalModuleList = {};
7
-
8
- constructor(externalModulePath, logger) {
9
- this._externalModuleList = {};
10
- this._logger = logger;
11
- this._externalModulePath = externalModulePath;
12
- }
13
-
14
- async load(modules) {
15
- for (const moduleName in modules) {
16
- if (Object.hasOwnProperty.call(modules, moduleName)) {
17
- const moduleFileName = modules[moduleName];
18
-
19
- try {
20
- const modulePath = `${this._externalModulePath}${moduleFileName}.js`;
21
-
22
- this._logger.info(`Attempting to load module ${moduleName} from ${modulePath}`);
23
-
24
- const module = await import(modulePath);
25
-
26
- this._externalModuleList[moduleName] = module;
27
-
28
- this._logger.info(`Module '${moduleName}' was loaded`);
29
- } catch (error) {
30
- this._logger.error(`Module '${moduleName}' failed during loading ${error}`);
31
- }
32
- }
33
- }
34
- }
35
-
36
- execute(name, requestInformation, data) {
37
- for (const moduleName in this._externalModuleList) {
38
- if (Object.hasOwnProperty.call(this._externalModuleList, moduleName) && moduleName === name) {
39
- const module = this._externalModuleList[moduleName];
40
-
41
- try {
42
- return module.process(requestInformation, data);
43
- } catch (error) {
44
- throw new HttpException(constants.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR, `Module ${moduleName} failed. ${error}`);
45
- }
46
-
47
- }
48
- }
49
-
50
- throw new HttpException(constants.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR, `Module ${moduleName} doesn't exists`);
51
- }
52
-
53
- }
54
-
1
+ const constants = require("./constants");
2
+ const HttpException = require('./HttpException');
3
+
4
+ class Proxy {
5
+
6
+ _externalModuleList = {};
7
+
8
+ constructor(externalModulePath, logger) {
9
+ this._externalModuleList = {};
10
+ this._logger = logger;
11
+ this._externalModulePath = externalModulePath;
12
+ }
13
+
14
+ async load(modules) {
15
+ for (const moduleName in modules) {
16
+ if (Object.hasOwnProperty.call(modules, moduleName)) {
17
+ const moduleFileName = modules[moduleName];
18
+
19
+ try {
20
+ const modulePath = `${this._externalModulePath}${moduleFileName}.js`;
21
+
22
+ this._logger.info(`Attempting to load module ${moduleName} from ${modulePath}`);
23
+
24
+ const module = await import(modulePath);
25
+
26
+ this._externalModuleList[moduleName] = module;
27
+
28
+ this._logger.info(`Module '${moduleName}' was loaded`);
29
+ } catch (error) {
30
+ this._logger.error(`Module '${moduleName}' failed during loading ${error}`);
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ execute(name, requestInformation, data) {
37
+ const module = this._externalModuleList[name];
38
+
39
+ if (!module) {
40
+ throw new HttpException(constants.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR, `Module ${name} doesn't exist`);
41
+ }
42
+
43
+ try {
44
+ return module.process(requestInformation, data);
45
+ } catch (error) {
46
+ throw new HttpException(constants.HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR, `Module ${name} failed. ${error}`);
47
+ }
48
+ }
49
+
50
+ }
51
+
55
52
  module.exports = Proxy;
@@ -1,43 +1,43 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const constants = require("./constants");
4
- const CSV = require('./csv');
5
- const HttpException = require('./HttpException');
6
-
7
- const text_reader = (file) => {
8
- return () => {
9
- if (!fs.existsSync(file)) {
10
- throw new HttpException(constants.HTTP_STATUS_CODES.NOT_FOUND, `File ${file} doesn't exists`);
11
- }
12
-
13
- return fs.readFileSync(file, 'utf8');
14
- };
15
- };
16
-
17
- const file_exists = (file) => fs.existsSync(file);
18
-
19
- const folder_reader = (folder) => {
20
- return (urlInformation) => {
21
-
22
- if (!urlInformation.hasFile) {
23
- throw new HttpException(constants.HTTP_STATUS_CODES.NOT_ACCEPTABLE, "File not provided");
24
- }
25
-
26
- const file = path.join(folder, urlInformation.file);
27
- return text_reader(file)()
28
- };
29
- };
30
-
31
- const csv_reader = function (file, parameters) {
32
- const csvContent = text_reader(file, parameters)();
33
- const csvReader = new CSV(csvContent, parameters);
34
-
35
- return csvReader.read.bind(csvReader);
36
- };
37
-
38
- module.exports = {
39
- text_reader: text_reader,
40
- folder_reader: folder_reader,
41
- csv_reader: csv_reader,
42
- file_exists: file_exists
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const constants = require("./constants");
4
+ const CSV = require('./csv');
5
+ const HttpException = require('./HttpException');
6
+
7
+ const text_reader = (file) => {
8
+ return () => {
9
+ if (!fs.existsSync(file)) {
10
+ throw new HttpException(constants.HTTP_STATUS_CODES.NOT_FOUND, `File ${file} doesn't exists`);
11
+ }
12
+
13
+ return fs.readFileSync(file, 'utf8');
14
+ };
15
+ };
16
+
17
+ const file_exists = (file) => fs.existsSync(file);
18
+
19
+ const folder_reader = (folder) => {
20
+ return (urlInformation) => {
21
+
22
+ if (!urlInformation.hasFile) {
23
+ throw new HttpException(constants.HTTP_STATUS_CODES.NOT_ACCEPTABLE, "File not provided");
24
+ }
25
+
26
+ const file = path.join(folder, urlInformation.file);
27
+ return text_reader(file)()
28
+ };
29
+ };
30
+
31
+ const csv_reader = function (file, parameters) {
32
+ const csvContent = text_reader(file, parameters)();
33
+ const csvReader = new CSV(csvContent, parameters);
34
+
35
+ return csvReader.read.bind(csvReader);
36
+ };
37
+
38
+ module.exports = {
39
+ text_reader: text_reader,
40
+ folder_reader: folder_reader,
41
+ csv_reader: csv_reader,
42
+ file_exists: file_exists
43
43
  };
@@ -1,23 +1,54 @@
1
- const constants = require("./constants");
2
-
3
- const parser = (url) => {
4
-
5
- const parsedUrl = new URL(url, constants.BASE_URL);
6
- const urlSections = parsedUrl.pathname.split("/").filter((e) => e !== "");
7
-
8
- const baseUrl = "/" + urlSections.filter((e) => e.indexOf(".") < 0).join("/");
9
- const file = urlSections.filter((e) => e.indexOf(".") >= 0);
10
- const hasFile = file.length > 0;
11
-
12
- return {
13
- base: baseUrl,
14
- file: hasFile ? file[0] : "",
15
- hasFile: hasFile,
16
- search: parsedUrl.searchParamss
17
- };
18
-
19
- };
20
-
21
- module.exports = {
22
- parse: parser
1
+ const constants = require("./constants");
2
+
3
+ const parser = (url) => {
4
+
5
+ const parsedUrl = new URL(url, constants.BASE_URL);
6
+ const urlSections = parsedUrl.pathname.split("/").filter((e) => e !== "");
7
+
8
+ const baseUrl = "/" + urlSections.filter((e) => e.indexOf(".") < 0).join("/");
9
+ const file = urlSections.filter((e) => e.indexOf(".") >= 0);
10
+ const hasFile = file.length > 0;
11
+
12
+ return {
13
+ pathname: parsedUrl.pathname,
14
+ base: baseUrl,
15
+ file: hasFile ? file[0] : "",
16
+ hasFile: hasFile,
17
+ search: parsedUrl.searchParams
18
+ };
19
+
20
+ };
21
+
22
+ /**
23
+ * Matches a request path against an endpoint pattern that may contain
24
+ * path parameters (e.g., /users/:id/orders/:orderId).
25
+ *
26
+ * @param {string} pattern - The endpoint pattern from the configuration.
27
+ * @param {string} requestPath - The actual incoming request base path.
28
+ * @returns {{ match: boolean, params: Object }} Whether it matched and extracted path parameters.
29
+ */
30
+ const matchPath = (pattern, requestPath) => {
31
+ const patternParts = pattern.split("/").filter((e) => e !== "");
32
+ const requestParts = requestPath.split("/").filter((e) => e !== "");
33
+
34
+ if (patternParts.length !== requestParts.length) {
35
+ return { match: false, params: {} };
36
+ }
37
+
38
+ const params = {};
39
+
40
+ for (let i = 0; i < patternParts.length; i++) {
41
+ if (patternParts[i].startsWith(":")) {
42
+ params[patternParts[i].substring(1)] = requestParts[i];
43
+ } else if (patternParts[i] !== requestParts[i]) {
44
+ return { match: false, params: {} };
45
+ }
46
+ }
47
+
48
+ return { match: true, params };
49
+ };
50
+
51
+ module.exports = {
52
+ parse: parser,
53
+ matchPath: matchPath
23
54
  };
package/package.json CHANGED
@@ -1,21 +1,39 @@
1
- {
2
- "name": "mockapi-msi",
3
- "version": "2.0.1",
4
- "description": "Mock API is a lightweight configurable HTTP API for testing and prototyping.",
5
- "main": "main.js",
6
- "scripts": {
7
- "start": "node ./main.js",
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "author": "Matias Iacono",
11
- "license": "ISC",
12
- "bin": {
13
- "mockapi": "main.js"
14
- },
15
- "engines": {
16
- "node": ">=16"
17
- },
18
- "dependencies": {
19
- "yaml": "2.0.0-5"
20
- }
1
+ {
2
+ "name": "mockapi-msi",
3
+ "version": "2.4.0",
4
+ "description": "Mock API is a lightweight configurable HTTP API for testing and prototyping.",
5
+ "main": "main.js",
6
+ "scripts": {
7
+ "start": "node ./main.js",
8
+ "test": "node --test tests/*.test.js"
9
+ },
10
+ "keywords": [
11
+ "mock",
12
+ "api",
13
+ "testing",
14
+ "prototyping",
15
+ "http",
16
+ "rest",
17
+ "fake-api",
18
+ "stub"
19
+ ],
20
+ "author": "Matias Iacono",
21
+ "license": "ISC",
22
+ "bin": {
23
+ "mockapi": "main.js"
24
+ },
25
+ "files": [
26
+ "main.js",
27
+ "modules/",
28
+ "apiHandlers/",
29
+ "testdata/",
30
+ "LICENSE",
31
+ "README.md"
32
+ ],
33
+ "engines": {
34
+ "node": ">=18"
35
+ },
36
+ "dependencies": {
37
+ "yaml": "2.2.2"
38
+ }
21
39
  }
package/testdata/data.csv CHANGED
@@ -1,6 +1,6 @@
1
- id,name,money
2
- 1,"test 1",100
3
- 2,"test 2",100
4
- 3,"test 3",100
5
- 4,"test, 4",100
1
+ id,name,money
2
+ 1,"test 1",100
3
+ 2,"test 2",100
4
+ 3,"test 3",100
5
+ 4,"test, 4",100
6
6
  5,"test 5",100
package/.dockerignore DELETED
@@ -1,24 +0,0 @@
1
- **/.classpath
2
- **/.dockerignore
3
- **/.env
4
- **/.git
5
- **/.gitignore
6
- **/.project
7
- **/.settings
8
- **/.toolstarget
9
- **/.vs
10
- **/.vscode
11
- **/*.*proj.user
12
- **/*.dbmdl
13
- **/*.jfm
14
- **/azds.yaml
15
- **/charts
16
- **/docker-compose*
17
- **/compose*
18
- **/Dockerfile*
19
- **/node_modules
20
- **/npm-debug.log
21
- **/obj
22
- **/secrets.dev.yaml
23
- **/values.dev.yaml
24
- README.md
package/.mockapi-config DELETED
@@ -1,48 +0,0 @@
1
-
2
- # basic Mock API configuration
3
- port: 8001
4
- enableCors: true
5
- #externalModulesPath: "apiHandlers/"
6
-
7
- # dummy example configurations
8
- # PATH must point to a existing CSV file
9
- # 3 native readers are supported: text | csv | folder
10
- data:
11
- myRows:
12
- path: "./testdata/data.csv"
13
- reader: csv
14
- properties:
15
- - json
16
- - seq
17
- - 0
18
- #options
19
- #json || text
20
- #seq || rand
21
- #-1 = return every record on every request
22
- #0...n starting index (always reset to 0 when reach EOR)
23
-
24
- # custom http response handlers section
25
- # use: handler unique name : file name within the previously declared folder
26
- #customHandlers:
27
- # "custom": "myCustomHandler"
28
-
29
- # Mock API available endpoints, return types and
30
- # general configuration
31
- # verb: any | get | post | delete | ...
32
- # data: refers to previously configured data and readers
33
- # responseStatus: 200 | 404 | 500 | ...
34
- # responseContentType: any MIME available type
35
- # handler: refers to any previously configured custom handler
36
- endpoints:
37
- "/data":
38
- verb: get
39
- data: myRows
40
- responseStatus: 200
41
- responseContentType: "application/json"
42
- #handler: "custom"
43
-
44
- log: verbose
45
- #debug
46
- #error
47
- #verbose
48
- #none
package/Dockerfile DELETED
@@ -1,8 +0,0 @@
1
- FROM node:12.18-alpine
2
- ENV NODE_ENV=production
3
- WORKDIR /usr/src/app
4
- COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
5
- RUN npm install --production --silent && mv node_modules ../
6
- COPY . .
7
- EXPOSE 8001
8
- CMD ["node", "main.js"]
@@ -1,14 +0,0 @@
1
- version: '3.4'
2
-
3
- services:
4
- mockapi:
5
- image: mockapi
6
- build:
7
- context: .
8
- dockerfile: ./Dockerfile
9
- environment:
10
- NODE_ENV: development
11
- ports:
12
- - 3000:3000
13
- - 9229:9229
14
- command: ["node", "--inspect=0.0.0.0:9229", "main.js"]
@@ -1,12 +0,0 @@
1
- version: '3.4'
2
-
3
- services:
4
- mockapi:
5
- image: mockapi
6
- build:
7
- context: .
8
- dockerfile: ./Dockerfile
9
- environment:
10
- NODE_ENV: production
11
- ports:
12
- - 3001:8001