@webtypen/webframez-core 0.0.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/.github/workflows/npm-publish.yml +31 -0
- package/README.md +148 -0
- package/index.ts +8 -0
- package/package.json +24 -0
- package/src/BaseKernel.ts +7 -0
- package/src/Controller/Controller.ts +1 -0
- package/src/Database/BaseDBDriver.ts +22 -0
- package/src/Database/DBConnection.ts +103 -0
- package/src/Database/DBDriver.ts +13 -0
- package/src/Database/Model.ts +135 -0
- package/src/Database/QueryBuilder.ts +65 -0
- package/src/Router/Request.ts +12 -0
- package/src/Router/Response.ts +61 -0
- package/src/Router/Route.ts +159 -0
- package/src/Router/Router.ts +295 -0
- package/src/WebApplication.ts +21 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Node.js Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [created]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish-gpr:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v3
|
|
12
|
+
- uses: actions/setup-node@v3
|
|
13
|
+
with:
|
|
14
|
+
node-version: 18
|
|
15
|
+
registry-url: https://npm.pkg.github.com/
|
|
16
|
+
- run: npm install
|
|
17
|
+
- run: npm publish
|
|
18
|
+
env:
|
|
19
|
+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
|
20
|
+
publish-npm:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v3
|
|
24
|
+
- uses: actions/setup-node@v3
|
|
25
|
+
with:
|
|
26
|
+
node-version: 18
|
|
27
|
+
registry-url: https://registry.npmjs.org/
|
|
28
|
+
- run: npm install
|
|
29
|
+
- run: npm publish --access public
|
|
30
|
+
env:
|
|
31
|
+
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# webtypen webframez Docs
|
|
2
|
+
|
|
3
|
+
## Controller
|
|
4
|
+
|
|
5
|
+
### Register a controller
|
|
6
|
+
|
|
7
|
+
A new controller is registered via the `controller` attribute in `app/Kernel.ts`. Just add a new entry for the controller to the object. The key of the object is the unique name of the controller, this is used again when connecting routes.
|
|
8
|
+
|
|
9
|
+
The controllers are initialized once when the web service is started. When calling a route, a single controller instance is created per request and thrown away after the request finishes.
|
|
10
|
+
|
|
11
|
+
## Routing
|
|
12
|
+
|
|
13
|
+
### Register a route
|
|
14
|
+
|
|
15
|
+
Routes are managed via the app/routes.ts. Routes can be registered and configured with the Route Facade. Routes can be associated strictly with a request method (GET, POST, PUT, DELETE) or all request methods (ANY):
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
Route.get("/", "TestController@test");
|
|
19
|
+
Route.post("/test2", "TestController@test");
|
|
20
|
+
Route.put("/test2", "TestController@test");
|
|
21
|
+
Route.delete("/test2", "TestController@test");
|
|
22
|
+
Route.any("/test2", "TestController@test");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The URL path is specified in the first parameter. The second parameter connects the route to a controller method. A previously registered controller can be connected using the syntax `[CONTROLLER]@[METHODE]`.
|
|
26
|
+
|
|
27
|
+
Alternatively, a function can be specified directly or a previously imported one can be used:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Directly
|
|
31
|
+
Route.get("/", (req: Request, res: Response) =>
|
|
32
|
+
res.send({ status: "success" })
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// Imported
|
|
36
|
+
import { myFunction } from "./myfunction";
|
|
37
|
+
Route.get("/", myFunction);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Register a middleware
|
|
41
|
+
|
|
42
|
+
Middleware functions are also registered in `app/Kernel.ts.` A middleware function can be associated with one or more routes. When calling these routes, the middleware function is called before executing the route logic. In this function, the request can be continued or aborted, for example, authorization rules can be implemented and easily reused for multiple routes.
|
|
43
|
+
|
|
44
|
+
Middleware functions are usually created under `app/Middleware`. A middleware function is called with the parameters (next, abort, req and res):
|
|
45
|
+
|
|
46
|
+
- `next`: Function that signals when called that the request may be continued
|
|
47
|
+
- `abort`: Function that aborts the request when called. An HTTP status code can be specified in the first parameter and a request body (usually text or JSON) in the second.
|
|
48
|
+
- `req`: The Request-Object
|
|
49
|
+
- `res`: The Response-Object
|
|
50
|
+
|
|
51
|
+
Alternatively, middleware functions can also be defined directly in Kernel.ts:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
static middleware: { [key: string]: any } = {
|
|
55
|
+
auth: async (next: any, abort: any, req: Request, res: Response) => {
|
|
56
|
+
console.log("auth-middleware");
|
|
57
|
+
next();
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A route can be connected to several middleware functions, which are called one after the other but before executing the route logic.
|
|
63
|
+
|
|
64
|
+
### Connect a route with a middleware
|
|
65
|
+
|
|
66
|
+
When registering a route, a configuration object can be passed in the third parameter. This can contain an array with middleware keys in the `middleware` parameter. The middlewares specified here are executed prior to executing the route logic when invoking this route. If a specified middleware aborts the request, it will not be executed:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
Route.get("/auth-data", "AuthController@authData", { middleware: ["auth"] });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Group routes
|
|
73
|
+
|
|
74
|
+
With the grouping of routes, the code of the application can be significantly reduced and kept clear. Here's how the following configurations can be used with a multiple route definition:
|
|
75
|
+
|
|
76
|
+
- `prefix`: A route path prefix used for all routes in this group:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
Route.group({ prefix: "/admin", () => {
|
|
80
|
+
Route.get("/dashboard", "AdminDashboardController@data");
|
|
81
|
+
// Path for this route would be: /admin/dashboard
|
|
82
|
+
}});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `middleware`: An array of middleware-keys used for all routes in this group:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
Route.group({ middleware: ["auth"], () => {
|
|
89
|
+
// Route with middleware auth
|
|
90
|
+
Route.get("/auth-data", "AuthController@authData");
|
|
91
|
+
|
|
92
|
+
// Route with middleware auth and admin
|
|
93
|
+
Route.get("/dashboard", "AdminDashboardController@data", { middleware: ["admin"] });
|
|
94
|
+
}});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The configuration parameters of a route group can of course be combined with each other.
|
|
98
|
+
|
|
99
|
+
Nesting of the route groups is also possible:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
Route.group({ prefix: "/test" }, () => {
|
|
103
|
+
Route.get("/", "TestController@test"); // Path: /test/
|
|
104
|
+
Route.get("/test2", "TestController@test"); // Path: /test2/
|
|
105
|
+
|
|
106
|
+
Route.group({ middleware: ["auth"], prefix: "/auth" }, () => {
|
|
107
|
+
Route.get("/data", "AuthController@data"); // Path: /test/auth/data; Middleware: auth
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Database
|
|
113
|
+
|
|
114
|
+
### Connect
|
|
115
|
+
|
|
116
|
+
The application can handle multiple database connections, but one is defined as the default connection and is automatically used by the system if models and database requests are not explicitly executed over another connection.
|
|
117
|
+
|
|
118
|
+
The connections are configured in the `config/database.ts` file. Each connection is given a unique key in the `connections` object and uses a driver. The following drivers are currently available:
|
|
119
|
+
|
|
120
|
+
- MongoDB Driver
|
|
121
|
+
|
|
122
|
+
Depending on the driver, the database connection must be configured with different parameters.
|
|
123
|
+
|
|
124
|
+
**MongoDB Connection example:**
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
export default {
|
|
128
|
+
defaultConnection: "default",
|
|
129
|
+
connections: {
|
|
130
|
+
["default"]: {
|
|
131
|
+
driver: "mongodb",
|
|
132
|
+
url: "mongodb://...",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Model
|
|
139
|
+
|
|
140
|
+
Models are usually placed under `app/Models`. Each model class inherits from `Model` and must store the table / collection name, in which the models data sets are stored, in the `__table` attribute.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { Model } from "@webtypen/webframez-core";
|
|
144
|
+
|
|
145
|
+
export class Test extends Model {
|
|
146
|
+
__table = "test_table";
|
|
147
|
+
}
|
|
148
|
+
```
|
package/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./src/BaseKernel";
|
|
2
|
+
export * from "./src/Controller/Controller";
|
|
3
|
+
export * from "./src/WebApplication";
|
|
4
|
+
export * from "./src/Router/Route";
|
|
5
|
+
export * from "./src/Router/Request";
|
|
6
|
+
export * from "./src/Router/Response";
|
|
7
|
+
export * from "./src/Database/Model";
|
|
8
|
+
export * from "./src/Database/QueryBuilder";
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webtypen/webframez-core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "The core package of the typescript based webframez (web-framework) by webtypen.de",
|
|
5
|
+
"homepage": "https://webtypen.de/",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Benedict Romp",
|
|
10
|
+
"email": "b.romp@webtypen.de",
|
|
11
|
+
"url": "https://webtypen.de/"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/webtypen/webframez-core/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/webtypen/webframez-core.git"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"dotenv": "^8.2.0",
|
|
22
|
+
"lodash": "^4.17.20"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class Controller {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Model } from "./Model";
|
|
2
|
+
import { QueryBuilder } from "./QueryBuilder";
|
|
3
|
+
|
|
4
|
+
export class BaseDBDriver {
|
|
5
|
+
config?: object;
|
|
6
|
+
|
|
7
|
+
setConfig(config: object) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async connect() {}
|
|
12
|
+
|
|
13
|
+
async close(client: any) {}
|
|
14
|
+
|
|
15
|
+
async handleQueryBuilder(client: any, queryBuilder: QueryBuilder) {}
|
|
16
|
+
|
|
17
|
+
async execute(client: any, data: any) {}
|
|
18
|
+
|
|
19
|
+
async onModelSave(model: Model, saveStatus: any | null | undefined) {
|
|
20
|
+
return model;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { DBDrivers } from "./DBDriver";
|
|
2
|
+
import dbconfig from "../../../../config/database";
|
|
3
|
+
import { QueryBuilder } from "./QueryBuilder";
|
|
4
|
+
|
|
5
|
+
class DBConnectionFacade {
|
|
6
|
+
connections: { [key: string]: any } = {};
|
|
7
|
+
|
|
8
|
+
getConnectionConfig(connection: string) {
|
|
9
|
+
if (!connection) {
|
|
10
|
+
connection = dbconfig.defaultConnection;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (
|
|
14
|
+
!connection ||
|
|
15
|
+
!dbconfig ||
|
|
16
|
+
!dbconfig.connections ||
|
|
17
|
+
!dbconfig.connections[connection as keyof {}]
|
|
18
|
+
) {
|
|
19
|
+
throw new Error("No connection given ...");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return dbconfig.connections[connection as keyof {}];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getConnectionDriver(connection: string) {
|
|
26
|
+
const config = this.getConnectionConfig(connection);
|
|
27
|
+
if (!config || !config["driver"]) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const driverClass = DBDrivers.get(config["driver"]);
|
|
32
|
+
const driver = new driverClass();
|
|
33
|
+
driver.setConfig(config);
|
|
34
|
+
return driver;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getConnection(connectionName?: string) {
|
|
38
|
+
if (!connectionName) {
|
|
39
|
+
connectionName = dbconfig.defaultConnection;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
this.connections[connectionName] &&
|
|
44
|
+
this.connections[connectionName].driver
|
|
45
|
+
) {
|
|
46
|
+
// Use cached connection
|
|
47
|
+
return this.connections[connectionName];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Create new connection and cache it
|
|
51
|
+
const driver = this.getConnectionDriver(connectionName);
|
|
52
|
+
const client = await driver.connect();
|
|
53
|
+
|
|
54
|
+
this.connections[connectionName] = {
|
|
55
|
+
driver: driver,
|
|
56
|
+
client: client,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return this.connections[connectionName];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async runQuery(query: QueryBuilder, options?: { [name: string]: any }) {
|
|
63
|
+
const connection = await this.getConnection();
|
|
64
|
+
const data = await connection.driver.handleQueryBuilder(
|
|
65
|
+
connection.client,
|
|
66
|
+
query
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (options && options.raw) {
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!data) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// @ToDo: Model-Mapping
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async execute(data: any, connectionName?: string) {
|
|
82
|
+
const connection = await this.getConnection(connectionName);
|
|
83
|
+
|
|
84
|
+
return await connection.driver.execute(connection.client, data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async getDriver(connectionName?: string) {
|
|
88
|
+
const connection = await this.getConnection(connectionName);
|
|
89
|
+
return connection.driver;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
mapDataToModel(model: any, data: any) {
|
|
93
|
+
const obj = new model();
|
|
94
|
+
if (data) {
|
|
95
|
+
for (let i in data) {
|
|
96
|
+
obj[i] = data[i];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return obj;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const DBConnection = new DBConnectionFacade();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class DBDriversFacade {
|
|
2
|
+
drivers: { [key: string]: any } = {};
|
|
3
|
+
|
|
4
|
+
register(name: string, component: any) {
|
|
5
|
+
this.drivers[name] = component;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
get(name: string) {
|
|
9
|
+
return this.drivers[name];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const DBDrivers = new DBDriversFacade();
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { DBConnection } from "./DBConnection";
|
|
2
|
+
import { QueryBuilder } from "./QueryBuilder";
|
|
3
|
+
|
|
4
|
+
export class Model {
|
|
5
|
+
[key: string]: any | undefined; // allow-custom-properties
|
|
6
|
+
__primaryKey = "_id";
|
|
7
|
+
__table: string = "";
|
|
8
|
+
__connection: string | undefined = undefined;
|
|
9
|
+
__hidden: string[] = [];
|
|
10
|
+
__unmapped: string[] = [];
|
|
11
|
+
__unmappedSystem: string[] = [
|
|
12
|
+
"__primaryKey",
|
|
13
|
+
"__table",
|
|
14
|
+
"__connection",
|
|
15
|
+
"__unmapped",
|
|
16
|
+
"__unmappedSystem",
|
|
17
|
+
"__is_deleted",
|
|
18
|
+
"__hidden",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new query-builder object and adds a where-clause
|
|
23
|
+
* @param column
|
|
24
|
+
* @param operator
|
|
25
|
+
* @param value
|
|
26
|
+
* @returns QueryBulder
|
|
27
|
+
*/
|
|
28
|
+
static where(column: any, operator: any, value: any): QueryBuilder {
|
|
29
|
+
const model = new this();
|
|
30
|
+
const queryBuilder = new QueryBuilder();
|
|
31
|
+
queryBuilder.setModelMapping(this);
|
|
32
|
+
queryBuilder.table(model.__table);
|
|
33
|
+
queryBuilder.where(column, operator, value);
|
|
34
|
+
|
|
35
|
+
return queryBuilder;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Executes a database-aggregation (mostly used by no-sql connections)
|
|
40
|
+
* @param aggregation
|
|
41
|
+
* @returns any
|
|
42
|
+
*/
|
|
43
|
+
static async aggregate(aggregation: any) {
|
|
44
|
+
const model = new this();
|
|
45
|
+
return await DBConnection.execute(
|
|
46
|
+
{
|
|
47
|
+
type: "aggregation",
|
|
48
|
+
table: model.__table,
|
|
49
|
+
aggregation: aggregation,
|
|
50
|
+
},
|
|
51
|
+
model.__connection
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the model-data without system- and unmapped-fields (new js-object)
|
|
57
|
+
* @returns object
|
|
58
|
+
*/
|
|
59
|
+
getModelData(): object {
|
|
60
|
+
const out: { [key: string]: any } = {};
|
|
61
|
+
for (let i in this) {
|
|
62
|
+
if (!this.__unmapped.includes(i) && !this.__unmappedSystem.includes(i)) {
|
|
63
|
+
out[i] = this[i];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns the model-data without system-, unmapped- and hidden-fields (new js-object)
|
|
71
|
+
* @returns object
|
|
72
|
+
*/
|
|
73
|
+
toArray(): object {
|
|
74
|
+
const out: { [key: string]: any } = {};
|
|
75
|
+
for (let i in this) {
|
|
76
|
+
if (
|
|
77
|
+
!this.__unmapped.includes(i) &&
|
|
78
|
+
!this.__unmappedSystem.includes(i) &&
|
|
79
|
+
!this.__hidden.includes(i)
|
|
80
|
+
) {
|
|
81
|
+
out[i] = this[i];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Saves the object in the database
|
|
89
|
+
* @returns Model
|
|
90
|
+
*/
|
|
91
|
+
async save() {
|
|
92
|
+
let status = null;
|
|
93
|
+
if (this[this.__primaryKey] !== undefined && this[this.__primaryKey]) {
|
|
94
|
+
// Update
|
|
95
|
+
status = await DBConnection.execute({
|
|
96
|
+
type: "updateOne",
|
|
97
|
+
table: this.__table,
|
|
98
|
+
primaryKey: this.__primaryKey,
|
|
99
|
+
filter: { [this.__primaryKey]: this[this.__primaryKey] },
|
|
100
|
+
data: this.getModelData(),
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
// Insert
|
|
104
|
+
status = await DBConnection.execute({
|
|
105
|
+
type: "insertOne",
|
|
106
|
+
table: this.__table,
|
|
107
|
+
data: this.getModelData(),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// onModelSave
|
|
112
|
+
const driver = await DBConnection.getDriver(this.__connection);
|
|
113
|
+
return driver.onModelSave(this, status);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Deletes the object from the database
|
|
118
|
+
* @returns boolean
|
|
119
|
+
*/
|
|
120
|
+
async delete() {
|
|
121
|
+
if (!this[this.__primaryKey]) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const queryBuilder = new QueryBuilder();
|
|
126
|
+
queryBuilder.setModelMapping(this);
|
|
127
|
+
queryBuilder.table(this.__table);
|
|
128
|
+
queryBuilder.where(this.__primaryKey, "=", this[this.__primaryKey]);
|
|
129
|
+
await queryBuilder.delete({ mode: "deleteOne" });
|
|
130
|
+
|
|
131
|
+
this.__is_deleted = true;
|
|
132
|
+
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { DBConnection } from "./DBConnection";
|
|
2
|
+
import { Model } from "./Model";
|
|
3
|
+
|
|
4
|
+
export class QueryBuilder {
|
|
5
|
+
database: string | null = null;
|
|
6
|
+
query: any[] = [];
|
|
7
|
+
queryTable: string = "";
|
|
8
|
+
mode = "get";
|
|
9
|
+
modelMapping = null;
|
|
10
|
+
|
|
11
|
+
setModelMapping(model?: any | null) {
|
|
12
|
+
this.modelMapping = model;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
table(table: string) {
|
|
16
|
+
this.queryTable = table;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
where(column: any, operator: any, value: any) {
|
|
20
|
+
this.query.push({
|
|
21
|
+
type: "where",
|
|
22
|
+
column: column,
|
|
23
|
+
operator: operator,
|
|
24
|
+
value: value,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async get(options?: any) {
|
|
29
|
+
this.mode = "get";
|
|
30
|
+
|
|
31
|
+
const result = await DBConnection.runQuery(this);
|
|
32
|
+
if (options && options.disableModelMapping) {
|
|
33
|
+
return result && result.length > 0 ? result : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result && result.length > 0 && this.modelMapping !== null
|
|
37
|
+
? result.map((el: Model) =>
|
|
38
|
+
DBConnection.mapDataToModel(this.modelMapping, el)
|
|
39
|
+
)
|
|
40
|
+
: result && result.length > 0
|
|
41
|
+
? result
|
|
42
|
+
: null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async first(options?: any) {
|
|
46
|
+
this.mode = "first";
|
|
47
|
+
|
|
48
|
+
const result = await DBConnection.runQuery(this);
|
|
49
|
+
if (options && options.disableModelMapping) {
|
|
50
|
+
return result ? result : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result && this.modelMapping !== null
|
|
54
|
+
? DBConnection.mapDataToModel(this.modelMapping, result)
|
|
55
|
+
: null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async delete(options?: { mode: string }) {
|
|
59
|
+
this.mode =
|
|
60
|
+
options && options.mode === "deleteOne" ? "deleteOne" : "delete";
|
|
61
|
+
|
|
62
|
+
await DBConnection.runQuery(this);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ServerResponse } from "http";
|
|
2
|
+
|
|
3
|
+
export class Response {
|
|
4
|
+
res?: ServerResponse;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sets the ServerResponse (res) Object (nodejs/http module)
|
|
8
|
+
* @param res
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
setServerResponse(res: ServerResponse) {
|
|
12
|
+
this.res = res;
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Set the http-status-code
|
|
18
|
+
*
|
|
19
|
+
* @param status
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
status(status: number): Response {
|
|
23
|
+
if (!this.res) {
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.res.statusCode = status;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Set a header attribute: Content-Type: application/json
|
|
33
|
+
*
|
|
34
|
+
* @param type
|
|
35
|
+
* @param value
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
header(type: string, value: string) {
|
|
39
|
+
if (!this.res) {
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.res.setHeader(type, value);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Sends data to the client
|
|
49
|
+
* Any objects will be stringified to JSON
|
|
50
|
+
*
|
|
51
|
+
* @param content
|
|
52
|
+
*/
|
|
53
|
+
send(content: any) {
|
|
54
|
+
if (typeof content === "object") {
|
|
55
|
+
this.res?.setHeader("Content-Type", "application/json");
|
|
56
|
+
this.res?.write(JSON.stringify(content));
|
|
57
|
+
} else {
|
|
58
|
+
this.res?.write(content);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Router } from "./Router";
|
|
2
|
+
|
|
3
|
+
export class RouteFacade {
|
|
4
|
+
tempGroupPrefix: string | null = null;
|
|
5
|
+
tempGroupMiddleware: string[] | null = null;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register a GET-Method
|
|
9
|
+
*
|
|
10
|
+
* @param path
|
|
11
|
+
* @param component
|
|
12
|
+
* @param options
|
|
13
|
+
*/
|
|
14
|
+
get(path: string, component: any, options?: { [key: string]: any }) {
|
|
15
|
+
Router.register(
|
|
16
|
+
"GET",
|
|
17
|
+
(this.tempGroupPrefix ? this.tempGroupPrefix : "") + path,
|
|
18
|
+
component,
|
|
19
|
+
options || this.tempGroupMiddleware
|
|
20
|
+
? {
|
|
21
|
+
...(options ? options : {}),
|
|
22
|
+
middleware:
|
|
23
|
+
this.tempGroupMiddleware || (options && options.middleware)
|
|
24
|
+
? [
|
|
25
|
+
...(this.tempGroupMiddleware
|
|
26
|
+
? this.tempGroupMiddleware
|
|
27
|
+
: []),
|
|
28
|
+
...(options && options.middleware
|
|
29
|
+
? options.middleware
|
|
30
|
+
: []),
|
|
31
|
+
]
|
|
32
|
+
: null,
|
|
33
|
+
}
|
|
34
|
+
: {}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register a POST-Method
|
|
40
|
+
*
|
|
41
|
+
* @param path
|
|
42
|
+
* @param component
|
|
43
|
+
* @param options
|
|
44
|
+
*/
|
|
45
|
+
post(path: string, component: any, options?: { [key: string]: any }) {
|
|
46
|
+
Router.register(
|
|
47
|
+
"POST",
|
|
48
|
+
(this.tempGroupPrefix ? this.tempGroupPrefix : "") + path,
|
|
49
|
+
component,
|
|
50
|
+
options || this.tempGroupMiddleware
|
|
51
|
+
? {
|
|
52
|
+
...(options ? options : {}),
|
|
53
|
+
middleware:
|
|
54
|
+
this.tempGroupMiddleware || (options && options.middleware)
|
|
55
|
+
? [
|
|
56
|
+
...(this.tempGroupMiddleware
|
|
57
|
+
? this.tempGroupMiddleware
|
|
58
|
+
: []),
|
|
59
|
+
...(options && options.middleware
|
|
60
|
+
? options.middleware
|
|
61
|
+
: []),
|
|
62
|
+
]
|
|
63
|
+
: null,
|
|
64
|
+
}
|
|
65
|
+
: {}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Register a PUT-Method
|
|
71
|
+
*
|
|
72
|
+
* @param path
|
|
73
|
+
* @param component
|
|
74
|
+
* @param options
|
|
75
|
+
*/
|
|
76
|
+
put(path: string, component: any, options?: { [key: string]: any }) {
|
|
77
|
+
Router.register(
|
|
78
|
+
"PUT",
|
|
79
|
+
(this.tempGroupPrefix ? this.tempGroupPrefix : "") + path,
|
|
80
|
+
component,
|
|
81
|
+
options || this.tempGroupMiddleware
|
|
82
|
+
? {
|
|
83
|
+
...(options ? options : {}),
|
|
84
|
+
middleware:
|
|
85
|
+
this.tempGroupMiddleware || (options && options.middleware)
|
|
86
|
+
? [
|
|
87
|
+
...(this.tempGroupMiddleware
|
|
88
|
+
? this.tempGroupMiddleware
|
|
89
|
+
: []),
|
|
90
|
+
...(options && options.middleware
|
|
91
|
+
? options.middleware
|
|
92
|
+
: []),
|
|
93
|
+
]
|
|
94
|
+
: null,
|
|
95
|
+
}
|
|
96
|
+
: {}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Register a DELETE-Method
|
|
102
|
+
*
|
|
103
|
+
* @param path
|
|
104
|
+
* @param component
|
|
105
|
+
* @param options
|
|
106
|
+
*/
|
|
107
|
+
delete(path: string, component: any, options?: { [key: string]: any }) {
|
|
108
|
+
Router.register(
|
|
109
|
+
"DELETE",
|
|
110
|
+
(this.tempGroupPrefix ? this.tempGroupPrefix : "") + path,
|
|
111
|
+
component,
|
|
112
|
+
options || this.tempGroupMiddleware
|
|
113
|
+
? {
|
|
114
|
+
...(options ? options : {}),
|
|
115
|
+
middleware:
|
|
116
|
+
this.tempGroupMiddleware || (options && options.middleware)
|
|
117
|
+
? [
|
|
118
|
+
...(this.tempGroupMiddleware
|
|
119
|
+
? this.tempGroupMiddleware
|
|
120
|
+
: []),
|
|
121
|
+
...(options && options.middleware
|
|
122
|
+
? options.middleware
|
|
123
|
+
: []),
|
|
124
|
+
]
|
|
125
|
+
: null,
|
|
126
|
+
}
|
|
127
|
+
: {}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
group(config: { [key: string]: any }, children: any) {
|
|
132
|
+
// Handle group prefix
|
|
133
|
+
if (config && config.prefix && config.prefix.trim() !== "") {
|
|
134
|
+
this.tempGroupPrefix =
|
|
135
|
+
(this.tempGroupPrefix ? this.tempGroupPrefix : "") + config.prefix;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Handle group middleware
|
|
139
|
+
if (config && config.middleware && config.middleware.length > 0) {
|
|
140
|
+
if (!this.tempGroupMiddleware || this.tempGroupMiddleware.length === 0) {
|
|
141
|
+
this.tempGroupMiddleware = config.middleware;
|
|
142
|
+
} else {
|
|
143
|
+
this.tempGroupMiddleware = [
|
|
144
|
+
...this.tempGroupMiddleware,
|
|
145
|
+
...config.middleware,
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Handle children / group body
|
|
151
|
+
children();
|
|
152
|
+
|
|
153
|
+
// Reset temp-group data
|
|
154
|
+
this.tempGroupPrefix = null;
|
|
155
|
+
this.tempGroupMiddleware = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const Route = new RouteFacade();
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import qs from "qs";
|
|
2
|
+
import { IncomingMessage, ServerResponse } from "http";
|
|
3
|
+
import { Response } from "./Response";
|
|
4
|
+
import { Kernel } from "../../../../app/Kernel";
|
|
5
|
+
|
|
6
|
+
type RouteObject = {
|
|
7
|
+
path: string;
|
|
8
|
+
component: any;
|
|
9
|
+
options: { [key: string]: any };
|
|
10
|
+
params: object;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
class RouterFacade {
|
|
14
|
+
/**
|
|
15
|
+
* GET Route Store
|
|
16
|
+
*/
|
|
17
|
+
routesGET: {
|
|
18
|
+
[key: string]: {
|
|
19
|
+
path: string;
|
|
20
|
+
component: any;
|
|
21
|
+
options: object;
|
|
22
|
+
params?: object;
|
|
23
|
+
};
|
|
24
|
+
} = {};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* POST Route Store
|
|
28
|
+
*/
|
|
29
|
+
routesPOST: {
|
|
30
|
+
[key: string]: {
|
|
31
|
+
path: string;
|
|
32
|
+
component: any;
|
|
33
|
+
options: object;
|
|
34
|
+
params?: object;
|
|
35
|
+
};
|
|
36
|
+
} = {};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* PUT Route Store
|
|
40
|
+
*/
|
|
41
|
+
routesPUT: {
|
|
42
|
+
[key: string]: {
|
|
43
|
+
path: string;
|
|
44
|
+
component: any;
|
|
45
|
+
options: object;
|
|
46
|
+
params?: object;
|
|
47
|
+
};
|
|
48
|
+
} = {};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* DELETE Route Store
|
|
52
|
+
*/
|
|
53
|
+
routesDELETE: {
|
|
54
|
+
[key: string]: {
|
|
55
|
+
path: string;
|
|
56
|
+
component: any;
|
|
57
|
+
options: object;
|
|
58
|
+
params?: object;
|
|
59
|
+
};
|
|
60
|
+
} = {};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Load the application-routes
|
|
64
|
+
*
|
|
65
|
+
*/
|
|
66
|
+
init() {
|
|
67
|
+
// Load routes
|
|
68
|
+
require(process.cwd() + "/app/routes");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Register a route
|
|
73
|
+
*
|
|
74
|
+
* @param type
|
|
75
|
+
* @param path
|
|
76
|
+
* @param component
|
|
77
|
+
* @param options
|
|
78
|
+
*/
|
|
79
|
+
register(type: string, path: string, component: any, options: object) {
|
|
80
|
+
if (type === "GET") {
|
|
81
|
+
this.routesGET[path] = {
|
|
82
|
+
path: path,
|
|
83
|
+
component: component,
|
|
84
|
+
options: options,
|
|
85
|
+
};
|
|
86
|
+
} else if (type === "POST") {
|
|
87
|
+
this.routesPOST[path] = {
|
|
88
|
+
path: path,
|
|
89
|
+
component: component,
|
|
90
|
+
options: options,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Loads the matching route based on the request-url
|
|
97
|
+
*
|
|
98
|
+
* @param req
|
|
99
|
+
* @returns
|
|
100
|
+
*/
|
|
101
|
+
dissolve(req: IncomingMessage): RouteObject | null {
|
|
102
|
+
if (!req.url) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (req.method === "GET") {
|
|
107
|
+
return this.dissolveRoute(this.routesGET, req.url);
|
|
108
|
+
} else if (req.method === "POST") {
|
|
109
|
+
return this.dissolveRoute(this.routesPOST, req.url);
|
|
110
|
+
} else if (req.method === "PUT") {
|
|
111
|
+
return this.dissolveRoute(this.routesPUT, req.url);
|
|
112
|
+
} else if (req.method === "DELETE") {
|
|
113
|
+
return this.dissolveRoute(this.routesDELETE, req.url);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Dissolves the matching route based on the request-url and an object of routes
|
|
120
|
+
*
|
|
121
|
+
* @param routes
|
|
122
|
+
* @param url
|
|
123
|
+
* @returns
|
|
124
|
+
*/
|
|
125
|
+
dissolveRoute(routes: any, url: string) {
|
|
126
|
+
if (routes[url]) {
|
|
127
|
+
// If url matches directly -> instant return
|
|
128
|
+
return { ...routes[url], params: {} };
|
|
129
|
+
} else {
|
|
130
|
+
// Try to find the matching route: Run through the slash-separated parts of the route
|
|
131
|
+
const partsRequest = url.split("/");
|
|
132
|
+
|
|
133
|
+
for (let path in routes) {
|
|
134
|
+
let status = true;
|
|
135
|
+
const parts = path.split("/");
|
|
136
|
+
const params: { [key: string]: any } = {};
|
|
137
|
+
|
|
138
|
+
for (let i in partsRequest) {
|
|
139
|
+
if (partsRequest[i] !== parts[i]) {
|
|
140
|
+
// Handle URL-Params
|
|
141
|
+
if (parts[i] && parts[i].trim().substring(0, 1) === ":") {
|
|
142
|
+
params[parts[i].trim().substring(1).toString()] = partsRequest[i];
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
status = false;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (status) {
|
|
152
|
+
return { ...routes[path], params: params };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Sends the default 404-Page
|
|
160
|
+
*
|
|
161
|
+
* @param res
|
|
162
|
+
*/
|
|
163
|
+
sendError(res: ServerResponse, code: number, message?: string) {
|
|
164
|
+
res.writeHead(code, { "Content-Type": "text/html" });
|
|
165
|
+
res.end(
|
|
166
|
+
message
|
|
167
|
+
? message
|
|
168
|
+
: code === 404
|
|
169
|
+
? "Oops! Page not found ..."
|
|
170
|
+
: "Oops! There was an unexpected error ..."
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Processes a request
|
|
176
|
+
*
|
|
177
|
+
* @param req
|
|
178
|
+
* @param res
|
|
179
|
+
*/
|
|
180
|
+
async handleRequest(req: IncomingMessage, res: ServerResponse) {
|
|
181
|
+
const route = this.dissolve(req);
|
|
182
|
+
|
|
183
|
+
// Check-Middleware
|
|
184
|
+
if (
|
|
185
|
+
route &&
|
|
186
|
+
route.options &&
|
|
187
|
+
route.options.middleware &&
|
|
188
|
+
route.options.middleware.length > 0
|
|
189
|
+
) {
|
|
190
|
+
for (let middlewareKey of route.options.middleware) {
|
|
191
|
+
const middleware = Kernel.middleware[middlewareKey];
|
|
192
|
+
if (!middleware) {
|
|
193
|
+
return this.sendError(
|
|
194
|
+
res,
|
|
195
|
+
500,
|
|
196
|
+
"Unknown middleware `" + middlewareKey + "` ..."
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
await new Promise((resolve, reject) => {
|
|
202
|
+
try {
|
|
203
|
+
middleware(
|
|
204
|
+
resolve,
|
|
205
|
+
(status: number, data: any) => {
|
|
206
|
+
reject({ status: status, data: data });
|
|
207
|
+
},
|
|
208
|
+
req,
|
|
209
|
+
res
|
|
210
|
+
);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
console.error(e);
|
|
213
|
+
|
|
214
|
+
return this.sendError(
|
|
215
|
+
res,
|
|
216
|
+
500,
|
|
217
|
+
"Error in middleware `" + middlewareKey + "` ..."
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
} catch (e: any) {
|
|
222
|
+
// Send Middleware-Abort
|
|
223
|
+
res.writeHead(
|
|
224
|
+
e.status,
|
|
225
|
+
typeof e.data === "object"
|
|
226
|
+
? { "Content-Type": "application/json" }
|
|
227
|
+
: { "Content-Type": "text/html" }
|
|
228
|
+
);
|
|
229
|
+
res.end(
|
|
230
|
+
typeof e.data === "object"
|
|
231
|
+
? JSON.stringify(e.data)
|
|
232
|
+
: e.data
|
|
233
|
+
? e.data
|
|
234
|
+
: " "
|
|
235
|
+
);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Resolve route-component (handle controller definition)
|
|
242
|
+
if (route && typeof route.component === "string") {
|
|
243
|
+
const split = route.component.split("@");
|
|
244
|
+
const controller = Kernel.controller[split[0]];
|
|
245
|
+
if (!controller) {
|
|
246
|
+
res.writeHead(500, { "Content-Type": "text/html" });
|
|
247
|
+
res.end("Controller `" + split[0] + "` not found ...");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Set Controller method as route-component
|
|
252
|
+
const controllerInstance = new controller();
|
|
253
|
+
route.component = controllerInstance[split[1]];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (route && route.component !== undefined) {
|
|
257
|
+
let body: any = [];
|
|
258
|
+
const bodyPlain: any = await new Promise((resolve: Function) => {
|
|
259
|
+
req
|
|
260
|
+
.on("data", (chunk) => {
|
|
261
|
+
body.push(chunk);
|
|
262
|
+
})
|
|
263
|
+
.on("end", () => {
|
|
264
|
+
resolve(Buffer.concat(body).toString());
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
await route.component(
|
|
270
|
+
{
|
|
271
|
+
body: bodyPlain ? qs.parse(bodyPlain) : {},
|
|
272
|
+
bodyPlain: bodyPlain,
|
|
273
|
+
params: route.params,
|
|
274
|
+
httpVersionMajor: req.httpVersionMajor,
|
|
275
|
+
httpVersionMinor: req.httpVersionMinor,
|
|
276
|
+
httpVersion: req.httpVersion,
|
|
277
|
+
headers: req.headers,
|
|
278
|
+
rawHeaders: req.rawHeaders,
|
|
279
|
+
url: req.url,
|
|
280
|
+
method: req.method,
|
|
281
|
+
},
|
|
282
|
+
new Response().setServerResponse(res)
|
|
283
|
+
);
|
|
284
|
+
res.end();
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.error(e);
|
|
287
|
+
this.sendError(res, 500);
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
this.sendError(res, 404);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export const Router = new RouterFacade();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import http, { Server } from "http";
|
|
2
|
+
import { Router } from "./Router/Router";
|
|
3
|
+
|
|
4
|
+
export class WebApplication {
|
|
5
|
+
private server!: Server;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Init the routes and start the http-server
|
|
9
|
+
*/
|
|
10
|
+
boot() {
|
|
11
|
+
Router.init();
|
|
12
|
+
|
|
13
|
+
this.server = http
|
|
14
|
+
.createServer((req, res) => {
|
|
15
|
+
Router.handleRequest(req, res);
|
|
16
|
+
})
|
|
17
|
+
.listen(3000, () => {
|
|
18
|
+
console.log("Server started and listening on port 3000");
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|