@forklaunch/core 0.1.1 → 0.1.2
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/.prettierignore +2 -0
- package/.prettierrc +6 -0
- package/dist/cache/index.d.ts +3 -0
- package/dist/cache/index.js +20 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interfaces/ttlCache.interface.d.ts +1 -1
- package/dist/cache/redisTtlCache.d.ts +3 -2
- package/dist/cache/redisTtlCache.js +2 -2
- package/dist/cache/redisTtlCache.js.map +1 -1
- package/dist/cache/types/{ttlCacheRecord.js → ttlCacheRecord.types.js} +1 -1
- package/dist/cache/types/ttlCacheRecord.types.js.map +1 -0
- package/dist/controllers/index.d.ts +1 -0
- package/dist/controllers/index.js +18 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/database/index.d.ts +1 -0
- package/dist/database/index.js +18 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mikro/models/entities/base.entity.js +1 -1
- package/dist/entityMapper/index.d.ts +2 -0
- package/dist/entityMapper/index.js +19 -0
- package/dist/entityMapper/index.js.map +1 -0
- package/dist/entityMapper/interfaces/entityMapper.interface.d.ts +3 -3
- package/dist/entityMapper/models/baseEntityMapper.model.d.ts +23 -23
- package/dist/entityMapper/models/baseEntityMapper.model.js +15 -15
- package/dist/entityMapper/models/baseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/requestEntityMapper.model.d.ts +17 -23
- package/dist/entityMapper/models/requestEntityMapper.model.js +13 -19
- package/dist/entityMapper/models/requestEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/models/responseEntityMapper.model.d.ts +15 -16
- package/dist/entityMapper/models/responseEntityMapper.model.js +8 -8
- package/dist/entityMapper/models/responseEntityMapper.model.js.map +1 -1
- package/dist/entityMapper/types/entityMapper.types.d.ts +3 -22
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +19 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/middlewares/index.d.ts +2 -0
- package/dist/http/middlewares/index.js +19 -0
- package/dist/http/middlewares/index.js.map +1 -0
- package/dist/http/middlewares/request.middleware.d.ts +11 -11
- package/dist/http/middlewares/request.middleware.js +23 -21
- package/dist/http/middlewares/request.middleware.js.map +1 -1
- package/dist/http/middlewares/response.middleware.d.ts +3 -3
- package/dist/http/middlewares/response.middleware.js +7 -3
- package/dist/http/middlewares/response.middleware.js.map +1 -1
- package/dist/http/types/api.types.d.ts +16 -12
- package/dist/http/types/index.d.ts +2 -0
- package/dist/http/types/index.js +19 -0
- package/dist/http/types/index.js.map +1 -0
- package/dist/http/types/primitive.types.d.ts +14 -13
- package/dist/index.d.ts +6 -1
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/interfaces/baseService.d.ts +1 -1
- package/dist/tests/{dto.test.js → entityMapper.test.js} +10 -32
- package/dist/tests/entityMapper.test.js.map +1 -0
- package/dist/tests/http.middleware.test.d.ts +1 -0
- package/dist/tests/http.middleware.test.js +79 -0
- package/dist/tests/http.middleware.test.js.map +1 -0
- package/dist/tests/redisTtlCache.test.js +32 -15
- package/dist/tests/redisTtlCache.test.js.map +1 -1
- package/entityMapper/index.ts +2 -0
- package/entityMapper/interfaces/entityMapper.interface.ts +11 -11
- package/entityMapper/models/baseEntityMapper.model.ts +90 -73
- package/entityMapper/models/requestEntityMapper.model.ts +96 -75
- package/entityMapper/models/responseEntityMapper.model.ts +83 -62
- package/entityMapper/types/entityMapper.types.ts +6 -23
- package/http/index.ts +2 -0
- package/http/middlewares/index.ts +2 -0
- package/http/middlewares/request.middleware.ts +103 -55
- package/http/middlewares/response.middleware.ts +56 -31
- package/http/types/api.types.ts +43 -25
- package/http/types/index.ts +2 -0
- package/http/types/primitive.types.ts +65 -44
- package/index.ts +6 -5
- package/jest.config.ts +2 -2
- package/package.json +13 -4
- package/tests/entityMapper.test.ts +219 -0
- package/tests/http.middleware.test.ts +99 -0
- package/tests/redisTtlCache.test.ts +49 -29
- package/dist/cache/types/ttlCacheRecord.js.map +0 -1
- package/dist/tests/dto.test.js.map +0 -1
- package/tests/dto.test.ts +0 -235
- /package/dist/cache/types/{ttlCacheRecord.d.ts → ttlCacheRecord.types.d.ts} +0 -0
- /package/dist/tests/{dto.test.d.ts → entityMapper.test.d.ts} +0 -0
package/http/types/api.types.ts
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
import { Prettify } from
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
import {
|
7
|
-
import {
|
1
|
+
import { Prettify } from '@forklaunch/common';
|
2
|
+
import {
|
3
|
+
AnySchemaValidator,
|
4
|
+
Schema
|
5
|
+
} from '@forklaunch/validator';
|
6
|
+
import { IdiomaticSchema, SchemaValidator } from '@forklaunch/validator/types';
|
7
|
+
import { IncomingHttpHeaders, OutgoingHttpHeader } from 'http';
|
8
|
+
import { ParsedQs } from 'qs';
|
9
|
+
import {
|
10
|
+
HttpContractDetails,
|
11
|
+
ParamsDictionary,
|
12
|
+
PathParamHttpContractDetails
|
13
|
+
} from './primitive.types';
|
8
14
|
|
9
15
|
export interface RequestContext {
|
10
16
|
correlationId: string;
|
@@ -12,15 +18,15 @@ export interface RequestContext {
|
|
12
18
|
}
|
13
19
|
|
14
20
|
export interface ForklaunchRequest<
|
15
|
-
SV extends
|
21
|
+
SV extends AnySchemaValidator,
|
16
22
|
P = ParamsDictionary,
|
17
|
-
ReqBody =
|
23
|
+
ReqBody = unknown,
|
18
24
|
ReqQuery = ParsedQs,
|
19
|
-
Headers = IncomingHttpHeaders
|
25
|
+
Headers = IncomingHttpHeaders
|
20
26
|
> {
|
21
27
|
context: Prettify<RequestContext>;
|
22
28
|
contractDetails: HttpContractDetails<SV> | PathParamHttpContractDetails<SV>;
|
23
|
-
schemaValidator:
|
29
|
+
schemaValidator: SchemaValidator;
|
24
30
|
|
25
31
|
params: P;
|
26
32
|
headers: Headers;
|
@@ -29,37 +35,49 @@ export interface ForklaunchRequest<
|
|
29
35
|
}
|
30
36
|
|
31
37
|
export interface ForklaunchResponse<
|
32
|
-
ResBody =
|
33
|
-
|
38
|
+
ResBody = {
|
39
|
+
400: unknown;
|
40
|
+
401: unknown;
|
41
|
+
403: unknown;
|
42
|
+
500: unknown;
|
43
|
+
},
|
44
|
+
StatusCode = number
|
34
45
|
> {
|
35
46
|
bodyData: unknown;
|
36
47
|
statusCode: StatusCode;
|
37
48
|
corked: boolean;
|
38
|
-
|
49
|
+
|
39
50
|
getHeaders: () => OutgoingHttpHeader;
|
40
51
|
setHeader: (key: string, value: string) => void;
|
41
52
|
status: {
|
42
53
|
<U extends keyof ResBody>(code: U): ForklaunchResponse<ResBody[U], U>;
|
43
|
-
<U extends keyof ResBody>(
|
54
|
+
<U extends keyof ResBody>(
|
55
|
+
code: U,
|
56
|
+
message?: string
|
57
|
+
): ForklaunchResponse<ResBody[U], U>;
|
44
58
|
<U extends 500>(code: U): ForklaunchResponse<string, U>;
|
45
59
|
<U extends 500>(code: U, message?: string): ForklaunchResponse<string, U>;
|
46
|
-
}
|
60
|
+
};
|
47
61
|
send: {
|
48
62
|
<T>(body?: ResBody, close_connection?: boolean): T;
|
49
63
|
<T>(body?: ResBody): T;
|
50
|
-
}
|
64
|
+
};
|
51
65
|
json: {
|
52
66
|
(body?: ResBody): boolean;
|
53
67
|
<T>(body?: ResBody): T;
|
54
|
-
}
|
68
|
+
};
|
55
69
|
jsonp: {
|
56
70
|
(body?: ResBody): boolean;
|
57
71
|
<T>(body?: ResBody): T;
|
58
|
-
}
|
72
|
+
};
|
59
73
|
}
|
60
|
-
export type MapSchema<
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
74
|
+
export type MapSchema<
|
75
|
+
SV extends AnySchemaValidator,
|
76
|
+
T extends IdiomaticSchema<SV> | SV['_ValidSchemaObject']
|
77
|
+
> =
|
78
|
+
Schema<T, SV> extends infer U
|
79
|
+
? { [key: string]: unknown } extends U
|
80
|
+
? never
|
81
|
+
: U
|
82
|
+
: never;
|
83
|
+
export type ForklaunchNextFunction = (err?: unknown) => void;
|
@@ -1,55 +1,76 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { UnboxedObjectSchema } from "@forklaunch/validator/types";
|
1
|
+
import { AnySchemaValidator } from '@forklaunch/validator';
|
2
|
+
import { UnboxedObjectSchema } from '@forklaunch/validator/types';
|
4
3
|
|
5
|
-
export type ParamsDictionary = { [key: string]: string
|
4
|
+
export type ParamsDictionary = { [key: string]: string };
|
6
5
|
|
7
|
-
export type StringOnlyObject<SV extends
|
8
|
-
|
6
|
+
export type StringOnlyObject<SV extends AnySchemaValidator> = Omit<
|
7
|
+
UnboxedObjectSchema<SV>,
|
8
|
+
number | symbol
|
9
|
+
>;
|
10
|
+
export type NumberOnlyObject<SV extends AnySchemaValidator> = Omit<
|
11
|
+
UnboxedObjectSchema<SV>,
|
12
|
+
string | symbol
|
13
|
+
>;
|
9
14
|
|
10
|
-
export type BodyObject<SV extends
|
11
|
-
|
12
|
-
export type
|
13
|
-
|
14
|
-
export type
|
15
|
+
export type BodyObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
16
|
+
unknown;
|
17
|
+
export type ParamsObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
18
|
+
unknown;
|
19
|
+
export type QueryObject<SV extends AnySchemaValidator> = StringOnlyObject<SV> &
|
20
|
+
unknown;
|
21
|
+
export type HeadersObject<SV extends AnySchemaValidator> =
|
22
|
+
StringOnlyObject<SV> & unknown;
|
23
|
+
export type ResponsesObject<SV extends AnySchemaValidator> = {
|
24
|
+
[key: number]:
|
25
|
+
| SV['_ValidSchemaObject']
|
26
|
+
| UnboxedObjectSchema<SV>
|
27
|
+
| string
|
28
|
+
| SV['string'];
|
29
|
+
} & unknown;
|
15
30
|
|
16
|
-
export type Body<SV extends
|
17
|
-
|
18
|
-
|
31
|
+
export type Body<SV extends AnySchemaValidator> =
|
32
|
+
| BodyObject<SV>
|
33
|
+
| SV['_ValidSchemaObject']
|
34
|
+
| SV['_SchemaCatchall'];
|
19
35
|
|
20
36
|
export type AuthMethod = 'jwt' | 'session';
|
21
37
|
export interface PathParamHttpContractDetails<
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
> {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
SV extends AnySchemaValidator,
|
39
|
+
ParamSchemas extends ParamsObject<SV> = ParamsObject<SV>,
|
40
|
+
ResponseSchemas extends ResponsesObject<SV> = ResponsesObject<SV>,
|
41
|
+
QuerySchemas extends QueryObject<SV> = QueryObject<SV>
|
42
|
+
> {
|
43
|
+
name: string;
|
44
|
+
summary: string;
|
45
|
+
responses: ResponseSchemas;
|
46
|
+
requestHeaders?: HeadersObject<SV>;
|
47
|
+
responseHeaders?: HeadersObject<SV>;
|
48
|
+
params?: ParamSchemas;
|
49
|
+
query?: QuerySchemas;
|
50
|
+
auth?: {
|
51
|
+
method: AuthMethod;
|
52
|
+
allowedSlugs?: Set<string>;
|
53
|
+
forbiddenSlugs?: Set<string>;
|
54
|
+
allowedRoles?: Set<string>;
|
55
|
+
forbiddenRoles?: Set<string>;
|
56
|
+
};
|
41
57
|
}
|
42
58
|
|
43
59
|
export interface HttpContractDetails<
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
> extends PathParamHttpContractDetails<
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
SV extends AnySchemaValidator,
|
61
|
+
ParamSchemas extends ParamsObject<SV> = ParamsObject<SV>,
|
62
|
+
ResponseSchemas extends ResponsesObject<SV> = ResponsesObject<SV>,
|
63
|
+
BodySchema extends Body<SV> = Body<SV>,
|
64
|
+
QuerySchemas extends QueryObject<SV> = QueryObject<SV>
|
65
|
+
> extends PathParamHttpContractDetails<
|
66
|
+
SV,
|
67
|
+
ParamSchemas,
|
68
|
+
ResponseSchemas,
|
69
|
+
QuerySchemas
|
70
|
+
> {
|
71
|
+
body?: BodySchema;
|
72
|
+
contentType?:
|
73
|
+
| 'application/json'
|
74
|
+
| 'multipart/form-data'
|
75
|
+
| 'application/x-www-form-urlencoded';
|
55
76
|
}
|
package/index.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
export * from './cache';
|
2
|
+
export * from './controllers';
|
3
|
+
export * from './database';
|
4
|
+
export * from './entityMapper';
|
5
|
+
export * from './http';
|
6
|
+
export * from './services';
|
package/jest.config.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {Config} from 'jest';
|
1
|
+
import type { Config } from 'jest';
|
2
2
|
|
3
3
|
const config: Config = {
|
4
4
|
verbose: true,
|
@@ -7,4 +7,4 @@ const config: Config = {
|
|
7
7
|
testPathIgnorePatterns: ['dist/', 'node_modules/']
|
8
8
|
};
|
9
9
|
|
10
|
-
export default config;
|
10
|
+
export default config;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@forklaunch/core",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.2",
|
4
4
|
"description": "forklaunch-js core package. Contains useful building blocks.",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
@@ -8,7 +8,8 @@
|
|
8
8
|
"build": "tsc",
|
9
9
|
"docs": "typedoc --out docs *",
|
10
10
|
"lint": "eslint . -c eslint.config.mjs",
|
11
|
-
"lint:fix": "eslint . -c eslint.config.mjs --fix"
|
11
|
+
"lint:fix": "eslint . -c eslint.config.mjs --fix",
|
12
|
+
"format": "prettier --ignore-path=.prettierignore --config .prettierrc '**/*.ts' --write"
|
12
13
|
},
|
13
14
|
"author": "Rohin Bhargava",
|
14
15
|
"license": "MIT",
|
@@ -21,7 +22,7 @@
|
|
21
22
|
},
|
22
23
|
"homepage": "https://github.com/forklaunch/forklaunch-js#readme",
|
23
24
|
"dependencies": {
|
24
|
-
"@forklaunch/validator": "^0.
|
25
|
+
"@forklaunch/validator": "^0.2.9",
|
25
26
|
"@mikro-orm/core": "^6.2.9",
|
26
27
|
"jose": "^5.6.2",
|
27
28
|
"redis": "^4.6.14",
|
@@ -35,6 +36,8 @@
|
|
35
36
|
"@types/redis": "^4.0.11",
|
36
37
|
"@types/uuid": "^10.0.0",
|
37
38
|
"globals": "^15.8.0",
|
39
|
+
"prettier": "^3.3.2",
|
40
|
+
"testcontainers": "^10.10.1",
|
38
41
|
"ts-jest": "^29.1.5",
|
39
42
|
"ts-node": "^10.9.2",
|
40
43
|
"typedoc": "^0.26.3",
|
@@ -43,5 +46,11 @@
|
|
43
46
|
},
|
44
47
|
"directories": {
|
45
48
|
"test": "tests"
|
49
|
+
},
|
50
|
+
"exports": {
|
51
|
+
".": {
|
52
|
+
"types": "./dist/index.d.ts",
|
53
|
+
"default": "./dist/index.js"
|
54
|
+
}
|
46
55
|
}
|
47
|
-
}
|
56
|
+
}
|
@@ -0,0 +1,219 @@
|
|
1
|
+
import {
|
2
|
+
TypeboxSchemaValidator,
|
3
|
+
number,
|
4
|
+
string
|
5
|
+
} from '@forklaunch/validator/typebox';
|
6
|
+
import { BaseEntity } from '../database/mikro/models/entities/base.entity';
|
7
|
+
import { RequestEntityMapper } from '../entityMapper/models/requestEntityMapper.model';
|
8
|
+
import { ResponseEntityMapper } from '../entityMapper/models/responseEntityMapper.model';
|
9
|
+
|
10
|
+
class TestEntity extends BaseEntity {
|
11
|
+
name: string;
|
12
|
+
age: number;
|
13
|
+
}
|
14
|
+
|
15
|
+
class TestRequestEntityMapper extends RequestEntityMapper<
|
16
|
+
TestEntity,
|
17
|
+
TypeboxSchemaValidator
|
18
|
+
> {
|
19
|
+
schema = {
|
20
|
+
id: string,
|
21
|
+
name: string,
|
22
|
+
age: number
|
23
|
+
};
|
24
|
+
|
25
|
+
toEntity(...additionalArgs: unknown[]): TestEntity {
|
26
|
+
const entity = new TestEntity();
|
27
|
+
entity.id = this.dto.id;
|
28
|
+
entity.name = this.dto.name;
|
29
|
+
entity.age = this.dto.age;
|
30
|
+
|
31
|
+
return entity;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
class TestResponseEntityMapper extends ResponseEntityMapper<
|
36
|
+
TestEntity,
|
37
|
+
TypeboxSchemaValidator
|
38
|
+
> {
|
39
|
+
schema = {
|
40
|
+
id: string,
|
41
|
+
name: string,
|
42
|
+
age: number
|
43
|
+
};
|
44
|
+
|
45
|
+
fromEntity(entity: TestEntity): this {
|
46
|
+
this.dto = {
|
47
|
+
id: entity.id,
|
48
|
+
name: entity.name,
|
49
|
+
age: entity.age
|
50
|
+
};
|
51
|
+
|
52
|
+
return this;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
function extractNonTimeBasedEntityFields<T extends BaseEntity>(entity: T): T {
|
57
|
+
entity.createdAt = new Date(0);
|
58
|
+
entity.updatedAt = new Date(0);
|
59
|
+
return entity;
|
60
|
+
}
|
61
|
+
|
62
|
+
describe('Request Entity Mapper Test', () => {
|
63
|
+
let TestRequestEM: TestRequestEntityMapper;
|
64
|
+
|
65
|
+
beforeAll(() => {
|
66
|
+
TestRequestEM = new TestRequestEntityMapper(new TypeboxSchemaValidator());
|
67
|
+
});
|
68
|
+
|
69
|
+
test('Schema Equality', async () => {
|
70
|
+
expect(TestRequestEM.schema).toEqual(TestRequestEntityMapper.schema());
|
71
|
+
});
|
72
|
+
|
73
|
+
test('From JSON', async () => {
|
74
|
+
const json = {
|
75
|
+
id: '123',
|
76
|
+
name: 'test',
|
77
|
+
age: 1
|
78
|
+
};
|
79
|
+
|
80
|
+
const responseEM = TestRequestEM.fromJson(json);
|
81
|
+
const staticEM = TestRequestEntityMapper.fromJson(
|
82
|
+
new TypeboxSchemaValidator(),
|
83
|
+
json
|
84
|
+
);
|
85
|
+
const expectedDto = {
|
86
|
+
id: '123',
|
87
|
+
name: 'test',
|
88
|
+
age: 1
|
89
|
+
};
|
90
|
+
|
91
|
+
expect(staticEM.dto).toEqual(expectedDto);
|
92
|
+
expect(responseEM.dto).toEqual(expectedDto);
|
93
|
+
expect(responseEM.dto).toEqual(staticEM.dto);
|
94
|
+
});
|
95
|
+
|
96
|
+
test('Deserialization Equality', async () => {
|
97
|
+
const json = {
|
98
|
+
id: '123',
|
99
|
+
name: 'test',
|
100
|
+
age: 1
|
101
|
+
};
|
102
|
+
|
103
|
+
const entity = extractNonTimeBasedEntityFields(
|
104
|
+
TestRequestEM.deserializeJsonToEntity(json)
|
105
|
+
);
|
106
|
+
const objectEntity = extractNonTimeBasedEntityFields(
|
107
|
+
TestRequestEM.fromJson(json).toEntity()
|
108
|
+
);
|
109
|
+
const staticEntity = extractNonTimeBasedEntityFields(
|
110
|
+
TestRequestEntityMapper.deserializeJsonToEntity(
|
111
|
+
new TypeboxSchemaValidator(),
|
112
|
+
json
|
113
|
+
)
|
114
|
+
);
|
115
|
+
let expectedEntity = new TestEntity();
|
116
|
+
expectedEntity.id = '123';
|
117
|
+
expectedEntity.name = 'test';
|
118
|
+
expectedEntity.age = 1;
|
119
|
+
|
120
|
+
expectedEntity = extractNonTimeBasedEntityFields(expectedEntity);
|
121
|
+
|
122
|
+
expect(entity).toEqual(expectedEntity);
|
123
|
+
expect(objectEntity).toEqual(expectedEntity);
|
124
|
+
expect(staticEntity).toEqual(expectedEntity);
|
125
|
+
expect(entity).toEqual(objectEntity);
|
126
|
+
expect(entity).toEqual(staticEntity);
|
127
|
+
expect(staticEntity).toEqual(expectedEntity);
|
128
|
+
expect(staticEntity).toEqual(objectEntity);
|
129
|
+
});
|
130
|
+
|
131
|
+
test('Serialization Failure', async () => {
|
132
|
+
const json = {
|
133
|
+
id: '123',
|
134
|
+
name: 'test'
|
135
|
+
};
|
136
|
+
|
137
|
+
// @ts-expect-error
|
138
|
+
expect(() => TestRequestEM.fromJson(json)).toThrow();
|
139
|
+
expect(() =>
|
140
|
+
// @ts-expect-error
|
141
|
+
TestRequestEntityMapper.fromJson(new TypeboxSchemaValidator(), json)
|
142
|
+
).toThrow();
|
143
|
+
});
|
144
|
+
});
|
145
|
+
|
146
|
+
describe('Response Entity Mapper Test', () => {
|
147
|
+
let TestResponseEM: TestResponseEntityMapper;
|
148
|
+
|
149
|
+
beforeAll(() => {
|
150
|
+
TestResponseEM = new TestResponseEntityMapper(new TypeboxSchemaValidator());
|
151
|
+
});
|
152
|
+
|
153
|
+
test('Schema Equality', async () => {
|
154
|
+
expect(TestResponseEM.schema).toEqual(TestResponseEntityMapper.schema());
|
155
|
+
});
|
156
|
+
|
157
|
+
test('From Entity', async () => {
|
158
|
+
const entity = new TestEntity();
|
159
|
+
entity.id = '123';
|
160
|
+
entity.name = 'test';
|
161
|
+
entity.age = 1;
|
162
|
+
|
163
|
+
const responseEM = TestResponseEM.fromEntity(entity);
|
164
|
+
const staticEM = TestResponseEntityMapper.fromEntity(
|
165
|
+
new TypeboxSchemaValidator(),
|
166
|
+
entity
|
167
|
+
);
|
168
|
+
const expectedDto = {
|
169
|
+
id: '123',
|
170
|
+
name: 'test',
|
171
|
+
age: 1
|
172
|
+
};
|
173
|
+
|
174
|
+
expect(staticEM.dto).toEqual(expectedDto);
|
175
|
+
expect(responseEM.dto).toEqual(expectedDto);
|
176
|
+
expect(responseEM.dto).toEqual(staticEM.dto);
|
177
|
+
});
|
178
|
+
|
179
|
+
test('Serialization Equality', async () => {
|
180
|
+
const entity = new TestEntity();
|
181
|
+
entity.id = '123';
|
182
|
+
entity.name = 'test';
|
183
|
+
entity.age = 1;
|
184
|
+
|
185
|
+
const json = TestResponseEM.serializeEntityToJson(entity);
|
186
|
+
const objectJson = TestResponseEM.fromEntity(entity).toJson();
|
187
|
+
const staticJson = TestResponseEntityMapper.serializeEntityToJson(
|
188
|
+
new TypeboxSchemaValidator(),
|
189
|
+
entity
|
190
|
+
);
|
191
|
+
const expectedJson = {
|
192
|
+
id: '123',
|
193
|
+
name: 'test',
|
194
|
+
age: 1
|
195
|
+
};
|
196
|
+
|
197
|
+
expect(json).toEqual(expectedJson);
|
198
|
+
expect(objectJson).toEqual(expectedJson);
|
199
|
+
expect(staticJson).toEqual(expectedJson);
|
200
|
+
expect(json).toEqual(objectJson);
|
201
|
+
expect(json).toEqual(staticJson);
|
202
|
+
expect(staticJson).toEqual(expectedJson);
|
203
|
+
expect(staticJson).toEqual(objectJson);
|
204
|
+
});
|
205
|
+
|
206
|
+
test('Serialization Failure', async () => {
|
207
|
+
const entity = new TestEntity();
|
208
|
+
entity.id = '123';
|
209
|
+
entity.name = 'test';
|
210
|
+
|
211
|
+
expect(() => TestResponseEM.fromEntity(entity).toJson()).toThrow();
|
212
|
+
expect(() =>
|
213
|
+
TestResponseEntityMapper.fromEntity(
|
214
|
+
new TypeboxSchemaValidator(),
|
215
|
+
entity
|
216
|
+
).toJson()
|
217
|
+
).toThrow();
|
218
|
+
});
|
219
|
+
});
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import { SchemaValidator } from '@forklaunch/validator';
|
2
|
+
import {
|
3
|
+
MockSchemaValidator,
|
4
|
+
literal,
|
5
|
+
mockSchemaValidator,
|
6
|
+
optional,
|
7
|
+
union
|
8
|
+
} from '@forklaunch/validator/tests/mockSchemaValidator';
|
9
|
+
import { ForklaunchRequest, ForklaunchResponse, HttpContractDetails, RequestContext, createRequestContext, enrichRequestDetails, parseRequestBody, parseRequestHeaders, parseRequestParams, parseRequestQuery, parseResponse } from '../http';
|
10
|
+
|
11
|
+
describe('Http Middleware Tests', () => {
|
12
|
+
let contractDetails: HttpContractDetails<MockSchemaValidator>;
|
13
|
+
let req: ForklaunchRequest<MockSchemaValidator>;
|
14
|
+
let resp: ForklaunchResponse;
|
15
|
+
|
16
|
+
const nextFunction = (err?: unknown) => {
|
17
|
+
expect(err).toBeFalsy()
|
18
|
+
};
|
19
|
+
|
20
|
+
const testSchema = {
|
21
|
+
test: union(['a', optional(literal('test'))] as const)
|
22
|
+
};
|
23
|
+
|
24
|
+
beforeAll(() => {
|
25
|
+
contractDetails = {
|
26
|
+
name: 'Test Contract',
|
27
|
+
summary: 'Test Contract Summary',
|
28
|
+
body: testSchema,
|
29
|
+
params: testSchema,
|
30
|
+
requestHeaders: testSchema,
|
31
|
+
query: testSchema,
|
32
|
+
responses: {
|
33
|
+
200: testSchema
|
34
|
+
}
|
35
|
+
};
|
36
|
+
|
37
|
+
req = {
|
38
|
+
context: {} as RequestContext,
|
39
|
+
contractDetails: {} as HttpContractDetails<MockSchemaValidator>,
|
40
|
+
schemaValidator: {} as SchemaValidator,
|
41
|
+
params: testSchema,
|
42
|
+
headers: testSchema,
|
43
|
+
body: testSchema,
|
44
|
+
query: testSchema
|
45
|
+
};
|
46
|
+
|
47
|
+
resp = {
|
48
|
+
bodyData: {},
|
49
|
+
statusCode: 200,
|
50
|
+
corked: false,
|
51
|
+
getHeaders: jest.fn(),
|
52
|
+
setHeader: jest.fn(),
|
53
|
+
status: jest.fn(),
|
54
|
+
send: jest.fn(),
|
55
|
+
json: jest.fn(),
|
56
|
+
jsonp: jest.fn(),
|
57
|
+
};
|
58
|
+
});
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
test('Create Request Context', async () => {
|
63
|
+
req.context = {} as RequestContext;
|
64
|
+
req.schemaValidator = {} as SchemaValidator;
|
65
|
+
createRequestContext(mockSchemaValidator)(req, resp, nextFunction);
|
66
|
+
expect(req.context.correlationId).not.toBe('123');
|
67
|
+
expect(req.schemaValidator).toBe(mockSchemaValidator);
|
68
|
+
});
|
69
|
+
|
70
|
+
test('Enrich Request Details', async () => {
|
71
|
+
req.contractDetails = {} as HttpContractDetails<MockSchemaValidator>;
|
72
|
+
enrichRequestDetails(contractDetails)(req, resp, nextFunction);
|
73
|
+
expect(req.contractDetails).toEqual(contractDetails);
|
74
|
+
});
|
75
|
+
|
76
|
+
test('Validate Request Params', async () => {
|
77
|
+
parseRequestParams(req, resp, nextFunction);
|
78
|
+
});
|
79
|
+
|
80
|
+
test('Validate Request Headers', async () => {
|
81
|
+
parseRequestHeaders(req, resp, nextFunction);
|
82
|
+
});
|
83
|
+
|
84
|
+
test('Validate Request Body', async () => {
|
85
|
+
parseRequestBody(req, resp, nextFunction);
|
86
|
+
});
|
87
|
+
|
88
|
+
test('Validate Request Query Params', async () => {
|
89
|
+
parseRequestQuery(req, resp, nextFunction);
|
90
|
+
});
|
91
|
+
|
92
|
+
test('Validate Response', async () => {
|
93
|
+
parseResponse(req, resp, nextFunction);
|
94
|
+
});
|
95
|
+
|
96
|
+
// Not supported yet
|
97
|
+
// test('Validate Auth', async () => {
|
98
|
+
// });
|
99
|
+
});
|