typescript-mock-server 0.0.7 → 0.0.10
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 +22 -12
- package/package.json +6 -3
- package/src/index.js +133 -0
- package/src/index.ts +36 -37
- package/tms-models/users/delete-1.ts +11 -0
- package/tms-models/users/get.ts +1 -1
- package/tms-models/users/head-1.ts +1 -0
- package/tms-models/users/options-1.ts +1 -0
- package/tms-models/users/patch-1.ts +11 -0
- package/tms-models/users/post-1.ts +11 -0
- package/tms-models/users/profile/get-1.ts +3 -2
- package/tms-models/users/put-1.ts +11 -0
- package/nodemon.json +0 -9
package/README.md
CHANGED
|
@@ -5,21 +5,26 @@ have to update your mock, otherwise you will receive compile errors.
|
|
|
5
5
|
|
|
6
6
|
# Quickstart
|
|
7
7
|
The easiest way to check out this stub/mock server is by installing it as a (dev)dependency and then
|
|
8
|
-
add a script to you scripts section: `
|
|
9
|
-
|
|
10
|
-
I am looking for a cleaner way of doing this. Your models should export a data const and your file should be named as `^(get|post){1}(-\d)?.ts$`.
|
|
8
|
+
add a script to you scripts section: `npm run --prefix node_modules/typescript-mock-server start -- --path=$(pwd)/tms-models`.
|
|
9
|
+
Your models should export a data const and your file should be named as `^(get|post){1}(-\d)?.ts$`.
|
|
11
10
|
Changes are being picked up automatically, so no need for a restart.
|
|
12
11
|
|
|
13
|
-
Check out the [working example project](https://github.com/GuyT07/typescript-mock-server-examle) and
|
|
12
|
+
Check out the [working example project](https://github.com/GuyT07/typescript-mock-server-examle) and [the source](https://github.com/GuyT07/typescript-mock-server/tree/main/tms-models/users).
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
# Options
|
|
15
|
+
- `--port=x`: Port number the server runs on
|
|
16
|
+
- `--path=x`: Path to your models
|
|
17
|
+
|
|
18
|
+
## Register mocks/stubs
|
|
16
19
|
Examples talk, so lets start with an example.
|
|
17
20
|
|
|
18
|
-
Your requirement is to have the following endpoints `/users`, `/users/1` and `/users/profile/1`
|
|
21
|
+
Your requirement is to have the following GET endpoints `/users`, `/users/1` and `/users/profile/1`
|
|
19
22
|
|
|
20
23
|
Create a root folder that contains your models, like `models`. Then add a folder `users` and within the newly created folder
|
|
21
|
-
create a new folder `profile`. Add following files `get.ts` and `get-1.ts` in the `users` directory, `get-1.ts` in the `profile` dir.
|
|
22
|
-
|
|
24
|
+
create a new folder `profile`. Add following files `get.ts` and `get-1.ts` in the `users` directory, `get-1.ts` in the `profile` dir.
|
|
25
|
+
To register another HTTP verb, you replace `get` with your verb ('get', 'post', 'put', 'delete', 'patch', 'options' and 'head' are currently supported).
|
|
26
|
+
|
|
27
|
+
You should have the following structure:
|
|
23
28
|
|
|
24
29
|
```
|
|
25
30
|
--models
|
|
@@ -65,8 +70,13 @@ Following dependencies are being used:
|
|
|
65
70
|
- @types/node
|
|
66
71
|
|
|
67
72
|
## Roadmap
|
|
68
|
-
- [
|
|
69
|
-
- [
|
|
70
|
-
- [ ] Support different headers
|
|
71
|
-
- [
|
|
73
|
+
- [x] Support other server port
|
|
74
|
+
- [x] Improve paths/way to start
|
|
75
|
+
- [ ] Support different headers/configurations (delays, status codes, ...)
|
|
76
|
+
- [x] Support all HTTP methods
|
|
77
|
+
- [ ] Add tests
|
|
78
|
+
- [ ] Refactor, split up in separate classes (first check if people actually want to use the tool)
|
|
79
|
+
- [ ] Setup CI/CD (+code quality + coverage tooling)
|
|
80
|
+
- [ ] Setup website
|
|
81
|
+
- [ ] Create a JVM compatible version
|
|
72
82
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typescript-mock-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "Simple mock server that can be used in front end development. Instead of creating json files you can just publish TypeScript objects as json",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
|
-
"example": "ts-node-dev src/index.ts --path
|
|
7
|
+
"example": "ts-node-dev src/index.ts --path=$(pwd)/tms-models --port=5000",
|
|
8
8
|
"start": "ts-node-dev src/index.ts"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
@@ -12,12 +12,15 @@
|
|
|
12
12
|
"url": "git+https://github.com/GuyT07/typescript-mock-server.git"
|
|
13
13
|
},
|
|
14
14
|
"keywords": ["mock server", "testing", "stub", "typescript"],
|
|
15
|
-
"author": "",
|
|
15
|
+
"author": "Guy Theuws",
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/GuyT07/typescript-mock-server/issues"
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://github.com/GuyT07/typescript-mock-server#readme",
|
|
21
|
+
"funding": {
|
|
22
|
+
"url" : "https://genydev.nl"
|
|
23
|
+
},
|
|
21
24
|
"devDependencies": {
|
|
22
25
|
"prettier": "^2.6.2"
|
|
23
26
|
},
|
package/src/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!./../node_modules/.bin/ts-node-dev
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
20
|
+
if (mod && mod.__esModule) return mod;
|
|
21
|
+
var result = {};
|
|
22
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
23
|
+
__setModuleDefault(result, mod);
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
27
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
28
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
29
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
30
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
31
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
32
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
36
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
37
|
+
var m = o[Symbol.asyncIterator], i;
|
|
38
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
39
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
40
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
41
|
+
};
|
|
42
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
43
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
44
|
+
};
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
const express_1 = __importDefault(require("express"));
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const baseDirPath = process.cwd();
|
|
49
|
+
console.log(baseDirPath);
|
|
50
|
+
const argv = (() => {
|
|
51
|
+
const args = {};
|
|
52
|
+
process.argv.slice(2).map((element) => {
|
|
53
|
+
const matches = element.match('--([a-zA-Z0-9]+)=(.*)');
|
|
54
|
+
if (matches) {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
args[matches[1]] = matches[2]
|
|
57
|
+
.replace(/^['"]/, '').replace(/['"]$/, '');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return args;
|
|
61
|
+
})();
|
|
62
|
+
console.log(argv);
|
|
63
|
+
// Create a new express app instance
|
|
64
|
+
const app = (0, express_1.default)();
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
const args = argv['path'];
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
const basePath = `${baseDirPath}/${args}`;
|
|
69
|
+
console.log('basePath:' + basePath);
|
|
70
|
+
function print(path) {
|
|
71
|
+
var e_1, _a;
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
console.log(path);
|
|
74
|
+
const dir = yield fs.promises.opendir(path);
|
|
75
|
+
try {
|
|
76
|
+
for (var dir_1 = __asyncValues(dir), dir_1_1; dir_1_1 = yield dir_1.next(), !dir_1_1.done;) {
|
|
77
|
+
const dirent = dir_1_1.value;
|
|
78
|
+
if (dirent.isDirectory()) {
|
|
79
|
+
yield print(`${path}/${dirent.name}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
handleFile(path, dirent);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
87
|
+
finally {
|
|
88
|
+
try {
|
|
89
|
+
if (dir_1_1 && !dir_1_1.done && (_a = dir_1.return)) yield _a.call(dir_1);
|
|
90
|
+
}
|
|
91
|
+
finally { if (e_1) throw e_1.error; }
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
print(basePath).catch(console.error);
|
|
96
|
+
function loadModule(moduleName) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
return yield Promise.resolve().then(() => __importStar(require(moduleName)));
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
app.listen(3000, function () {
|
|
102
|
+
console.log('App is listening on port 3000!');
|
|
103
|
+
});
|
|
104
|
+
function handleFile(path, dirent) {
|
|
105
|
+
console.log('File name: ' + dirent.name);
|
|
106
|
+
if (dirent.name.startsWith('get')) {
|
|
107
|
+
handleGetRequest(path, dirent);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function addEndpoint(endpoint, model) {
|
|
111
|
+
app.get(endpoint, function (req, res) {
|
|
112
|
+
res.send(model.data);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function handleGetRequest(path, dirent) {
|
|
116
|
+
console.log('Adding GET request');
|
|
117
|
+
const endpoint = convertFileNameToEndpoint(path, dirent);
|
|
118
|
+
console.log('Endpoint: ' + endpoint);
|
|
119
|
+
const modulePath = `${path}/${dirent.name}`;
|
|
120
|
+
console.log('Resolve module: ' + modulePath);
|
|
121
|
+
loadModule(modulePath)
|
|
122
|
+
.then(model => addEndpoint(endpoint, model))
|
|
123
|
+
.catch(err => console.error(err));
|
|
124
|
+
}
|
|
125
|
+
function convertFileNameToEndpoint(path, dirent) {
|
|
126
|
+
let endpoint = `${path.replace(basePath, '')}/${dirent.name}`;
|
|
127
|
+
endpoint = endpoint.replace('.ts', '');
|
|
128
|
+
endpoint = endpoint.replace('get', '');
|
|
129
|
+
if (endpoint !== '') {
|
|
130
|
+
endpoint = endpoint.replace('-', '');
|
|
131
|
+
}
|
|
132
|
+
return endpoint;
|
|
133
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
#!./node_modules/.bin/ts-node-dev
|
|
2
2
|
|
|
3
3
|
import express, { Express } from 'express';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
console.log(baseDirPath);
|
|
6
|
+
type HttpVerb = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head';
|
|
8
7
|
|
|
9
|
-
const argv = (() => {
|
|
8
|
+
const argv: { [key: string]: string } = (() => {
|
|
10
9
|
const args = {};
|
|
11
10
|
process.argv.slice(2).map((element) => {
|
|
12
11
|
const matches = element.match('--([a-zA-Z0-9]+)=(.*)');
|
|
@@ -19,71 +18,71 @@ const argv = (() => {
|
|
|
19
18
|
return args;
|
|
20
19
|
})();
|
|
21
20
|
|
|
22
|
-
console.log(argv);
|
|
21
|
+
console.log(`Passed arguments %o`, argv);
|
|
23
22
|
|
|
24
23
|
// Create a new express app instance
|
|
25
24
|
const app: Express = express();
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
const args = argv['path'];
|
|
26
|
+
const { path, port } = argv;
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const basePath = `${path}`;
|
|
29
|
+
|
|
30
|
+
interface RegisteredEndpoint {
|
|
31
|
+
httpVerb: string;
|
|
32
|
+
endpoint: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const registeredEndpoints: RegisteredEndpoint[] = [];
|
|
32
36
|
|
|
33
37
|
console.log('basePath:' + basePath);
|
|
34
38
|
|
|
35
|
-
async function
|
|
36
|
-
console.log(path);
|
|
39
|
+
async function readRoutes(path: string) {
|
|
37
40
|
const dir = await fs.promises.opendir(path);
|
|
38
41
|
for await (const dirent of dir) {
|
|
39
42
|
if (dirent.isDirectory()) {
|
|
40
|
-
await
|
|
43
|
+
await readRoutes(`${path}/${dirent.name}`);
|
|
41
44
|
} else {
|
|
42
45
|
handleFile(path, dirent);
|
|
43
46
|
}
|
|
44
47
|
}
|
|
48
|
+
registeredEndpoints.forEach(endpoint => console.log(`${endpoint.httpVerb.toUpperCase()} http://localhost:${port}${endpoint.endpoint}`))
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
readRoutes(basePath).catch(console.error);
|
|
52
|
+
|
|
53
|
+
app.listen(port || 3000, function() {
|
|
54
|
+
console.log(`App is listening on port ${port || 3000}!`);
|
|
55
|
+
});
|
|
48
56
|
|
|
49
57
|
async function loadModule(moduleName: string) {
|
|
50
58
|
return await import(moduleName);
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
app.listen(3000, function() {
|
|
54
|
-
console.log('App is listening on port 3000!');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
61
|
function handleFile(path: string, dirent: fs.Dirent) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
handleGetRequest(path, dirent);
|
|
61
|
-
}
|
|
62
|
+
const httpVerb = (dirent.name.indexOf('-') > -1 ? dirent.name.split('-')[0] : dirent.name.split('.')[0]) as HttpVerb;
|
|
63
|
+
handleRequest(path, dirent, httpVerb);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
function addEndpoint(endpoint: string, model: any) {
|
|
65
|
-
app
|
|
66
|
-
res.send(model.data);
|
|
67
|
-
});
|
|
66
|
+
function addEndpoint(endpoint: string, httpVerb: HttpVerb, model: any) {
|
|
67
|
+
app[httpVerb](endpoint, (req, res) => res.send(model.data));
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
const endpoint = convertFileNameToEndpoint(path, dirent);
|
|
73
|
-
console.log('Endpoint: ' + endpoint);
|
|
70
|
+
function handleRequest(path: string, dirent: fs.Dirent, httpVerb: HttpVerb) {
|
|
71
|
+
const endpoint = convertFileNameToEndpoint(path, dirent, httpVerb);
|
|
74
72
|
const modulePath = `${path}/${dirent.name}`;
|
|
75
|
-
|
|
73
|
+
registeredEndpoints.push({httpVerb, endpoint});
|
|
76
74
|
loadModule(modulePath)
|
|
77
|
-
.then(model => addEndpoint(endpoint, model))
|
|
75
|
+
.then(model => addEndpoint(endpoint, httpVerb, model))
|
|
78
76
|
.catch(err => console.error(err));
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
function convertFileNameToEndpoint(path: string, dirent: fs.Dirent): string {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
function convertFileNameToEndpoint(path: string, dirent: fs.Dirent, httpVerb: HttpVerb): string {
|
|
80
|
+
const endpoint = `${path.replace(basePath, '')}/${dirent.name}`
|
|
81
|
+
.replace('.ts', '')
|
|
82
|
+
.replace(httpVerb, '')
|
|
83
|
+
.replace('-', '');
|
|
84
|
+
if (endpoint.endsWith('/')) {
|
|
85
|
+
return endpoint.substring(0, endpoint.length - 1);
|
|
87
86
|
}
|
|
88
87
|
return endpoint;
|
|
89
88
|
}
|
package/tms-models/users/get.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const data = null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const data = null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { User } from '../get';
|
|
1
|
+
import { newDate, User } from '../get';
|
|
2
2
|
|
|
3
3
|
interface Profile {
|
|
4
4
|
id: number;
|
|
@@ -10,6 +10,7 @@ export const data: Profile = {
|
|
|
10
10
|
id: 1, title: 'Hello profile', user: {
|
|
11
11
|
id: 1,
|
|
12
12
|
firstName: 'Guy',
|
|
13
|
-
lastName: 'Theuws'
|
|
13
|
+
lastName: 'Theuws',
|
|
14
|
+
creationDate: newDate()
|
|
14
15
|
}
|
|
15
16
|
};
|