snap-on-openapi 1.0.1 → 1.0.3
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 +15 -15
- package/dist/OpenApi.d.ts +23 -23
- package/dist/OpenApi.js +17 -17
- package/dist/OpenApi.test.d.ts +1 -0
- package/dist/OpenApi.test.js +418 -0
- package/dist/README.md +15 -15
- package/dist/index.d.ts +38 -38
- package/dist/index.js +22 -22
- package/dist/services/ClientGenerator/ClientGenerator.d.ts +2 -2
- package/dist/services/ClientGenerator/ClientGenerator.test.d.ts +1 -0
- package/dist/services/ClientGenerator/ClientGenerator.test.js +37 -0
- package/dist/services/ConfigBuilder/ConfigBuilder.d.ts +9 -9
- package/dist/services/ConfigBuilder/ConfigBuilder.js +1 -1
- package/dist/services/ConfigBuilder/ConfigBuilder.test.d.ts +1 -0
- package/dist/services/ConfigBuilder/ConfigBuilder.test.js +207 -0
- package/dist/services/ConfigBuilder/types/DefaultConfig.d.ts +9 -9
- package/dist/services/ConfigBuilder/types/DefaultConfig.js +6 -6
- package/dist/services/ConfigBuilder/types/DefaultConfig.test.d.ts +1 -0
- package/dist/services/ConfigBuilder/types/DefaultConfig.test.js +82 -0
- package/dist/services/ConfigBuilder/types/DefaultErrorMap.d.ts +7 -7
- package/dist/services/ConfigBuilder/types/DefaultErrorMap.js +4 -4
- package/dist/services/ConfigBuilder/types/DefaultRouteContextMap.d.ts +3 -3
- package/dist/services/ConfigBuilder/types/DefaultRouteMap.d.ts +5 -5
- package/dist/services/ConfigBuilder/types/DefaultRouteMap.js +2 -2
- package/dist/services/ConfigBuilder/types/DefaultRouteParamsMap.d.ts +2 -2
- package/dist/services/ConfigBuilder/types/OpenApiConstructor.d.ts +1 -1
- package/dist/services/DescriptionChecker/DescriptionChecker.d.ts +2 -2
- package/dist/services/DescriptionChecker/DescriptionChecker.js +1 -1
- package/dist/services/DescriptionChecker/DescriptionChecker.test.d.ts +1 -0
- package/dist/services/DescriptionChecker/DescriptionChecker.test.js +120 -0
- package/dist/services/DevelopmentUtils/DevelopmentUtils.test.d.ts +1 -0
- package/dist/services/DevelopmentUtils/DevelopmentUtils.test.js +10 -0
- package/dist/services/ExpressWrapper/ExpressWrapper.d.ts +5 -5
- package/dist/services/ExpressWrapper/ExpressWrapper.js +1 -1
- package/dist/services/ExpressWrapper/ExpressWrapper.test.d.ts +1 -0
- package/dist/services/ExpressWrapper/ExpressWrapper.test.js +136 -0
- package/dist/services/ExpressWrapper/types/ExpressApp.d.ts +1 -1
- package/dist/services/ExpressWrapper/types/ExpressHandler.d.ts +2 -2
- package/dist/services/Logger/Logger.d.ts +2 -1
- package/dist/services/Logger/Logger.js +4 -1
- package/dist/services/Logger/Logger.test.d.ts +1 -0
- package/dist/services/Logger/Logger.test.js +113 -0
- package/dist/services/RoutingFactory/RoutingFactory.d.ts +4 -4
- package/dist/services/SchemaGenerator/SchemaGenerator.d.ts +6 -6
- package/dist/services/SchemaGenerator/SchemaGenerator.js +3 -4
- package/dist/services/SchemaGenerator/SchemaGenerator.test.d.ts +1 -0
- package/dist/services/SchemaGenerator/SchemaGenerator.test.js +142 -0
- package/dist/services/TanstackStartWrapper/TanstackStartWrapper.d.ts +4 -4
- package/dist/services/TanstackStartWrapper/TanstackStartWrapper.js +1 -1
- package/dist/services/TanstackStartWrapper/TanstackStartWrapper.test.d.ts +1 -0
- package/dist/services/TanstackStartWrapper/TanstackStartWrapper.test.js +44 -0
- package/dist/services/TestUtils/TestUtils.d.ts +5 -5
- package/dist/services/TestUtils/TestUtils.js +3 -3
- package/dist/services/TestUtils/TestUtils.test.d.ts +1 -0
- package/dist/services/TestUtils/TestUtils.test.js +20 -0
- package/dist/services/ValidationUtils/ValidationUtils.js +3 -3
- package/dist/services/ValidationUtils/ValidationUtils.test.d.ts +1 -0
- package/dist/services/ValidationUtils/ValidationUtils.test.js +165 -0
- package/dist/services/ValidationUtils/transformers/stringBooleanTransformer.test.d.ts +1 -0
- package/dist/services/ValidationUtils/transformers/stringBooleanTransformer.test.js +19 -0
- package/dist/services/ValidationUtils/transformers/stringDateTransformer.test.d.ts +1 -0
- package/dist/services/ValidationUtils/transformers/stringDateTransformer.test.js +13 -0
- package/dist/services/ValidationUtils/transformers/stringNumberTransfromer.test.d.ts +1 -0
- package/dist/services/ValidationUtils/transformers/stringNumberTransfromer.test.js +47 -0
- package/dist/types/AnyRoute.d.ts +1 -1
- package/dist/types/InitialBuilder.d.ts +8 -8
- package/dist/types/Route.d.ts +2 -2
- package/dist/types/RouteMap.d.ts +2 -2
- package/dist/types/Wrappers.d.ts +3 -3
- package/dist/types/config/AnyConfig.d.ts +3 -3
- package/dist/types/config/AnyRouteConfigMap.d.ts +1 -1
- package/dist/types/config/Config.d.ts +10 -8
- package/dist/types/config/ContextParams.d.ts +2 -2
- package/dist/types/config/ErrorConfigMap.d.ts +1 -1
- package/dist/types/config/ErrorResponse.d.ts +1 -1
- package/dist/types/config/Info.d.ts +1 -1
- package/dist/types/config/RouteConfig.d.ts +1 -1
- package/dist/types/config/RouteConfigMap.d.ts +3 -3
- package/dist/types/config/RouteContextMap.d.ts +2 -2
- package/dist/types/config/Server.d.ts +1 -1
- package/dist/types/errors/BuiltInError.d.ts +2 -2
- package/dist/types/errors/BuiltInError.js +1 -1
- package/dist/types/errors/ValidationError.d.ts +2 -2
- package/dist/types/errors/ValidationError.js +2 -2
- package/dist/types/errors/responses/NotFoundErrorResponse.d.ts +1 -1
- package/dist/types/errors/responses/NotFoundErrorResponse.js +1 -1
- package/dist/types/errors/responses/UnknownErrorResponse.d.ts +1 -1
- package/dist/types/errors/responses/UnknownErrorResponse.js +1 -1
- package/dist/types/errors/responses/ValidationErrorResponse.d.ts +2 -2
- package/dist/types/errors/responses/ValidationErrorResponse.js +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
import { OpenApi } from '../../../OpenApi';
|
|
4
|
+
import { ErrorCode } from '../../../enums/ErrorCode';
|
|
5
|
+
import { Method } from '../../../enums/Methods';
|
|
6
|
+
import { SampleRouteType } from '../../../enums/SampleRouteType';
|
|
7
|
+
import { TestUtils } from '../../TestUtils/TestUtils';
|
|
8
|
+
describe('DefaultConfig', () => {
|
|
9
|
+
describe('Error handler', () => {
|
|
10
|
+
test('Default Config checks', async () => {
|
|
11
|
+
const defaultApi = OpenApi.builder.create();
|
|
12
|
+
expect(defaultApi.getConfig().skipDescriptionsCheck, 'By default we check validator descriptions').toBe(false);
|
|
13
|
+
});
|
|
14
|
+
test('Returns not found error on unkown route', async () => {
|
|
15
|
+
const defaultApi = OpenApi.builder.create();
|
|
16
|
+
const req = TestUtils.createRequest('/api/route');
|
|
17
|
+
const res = await defaultApi.processRootRoute(req);
|
|
18
|
+
expect(res.body, 'Should throw error since no route is present').toEqual({
|
|
19
|
+
error: ErrorCode.NotFound,
|
|
20
|
+
});
|
|
21
|
+
expect(res.status, 'Should status 404 for not found error').toEqual(404);
|
|
22
|
+
});
|
|
23
|
+
test('Returns unknown error on random error', async () => {
|
|
24
|
+
const defaultApi = OpenApi.builder.create();
|
|
25
|
+
const route = defaultApi.factory.createRoute({
|
|
26
|
+
type: SampleRouteType.Public,
|
|
27
|
+
method: Method.GET,
|
|
28
|
+
path: '/route',
|
|
29
|
+
description: 'Test route',
|
|
30
|
+
validators: {
|
|
31
|
+
response: z.string().openapi({ description: 'Test response' }),
|
|
32
|
+
},
|
|
33
|
+
handler: async () => {
|
|
34
|
+
throw new Error('dasdsaa');
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
defaultApi.addRoute(route);
|
|
38
|
+
const req = TestUtils.createRequest('/api/route');
|
|
39
|
+
const res = await defaultApi.processRootRoute(req);
|
|
40
|
+
expect(res.body, 'Should return unknown error if error happens').toEqual({
|
|
41
|
+
error: ErrorCode.UnknownError,
|
|
42
|
+
});
|
|
43
|
+
expect(res.status, 'Should status 500 for unknown error').toEqual(500);
|
|
44
|
+
});
|
|
45
|
+
test('Returns validation error on invalid params', async () => {
|
|
46
|
+
const defaultApi = OpenApi.builder.create();
|
|
47
|
+
const route = defaultApi.factory.createRoute({
|
|
48
|
+
type: SampleRouteType.Public,
|
|
49
|
+
method: Method.POST,
|
|
50
|
+
path: '/route',
|
|
51
|
+
description: 'Test route',
|
|
52
|
+
validators: {
|
|
53
|
+
body: z.object({
|
|
54
|
+
name: z.string().openapi({ description: 'Name' }),
|
|
55
|
+
}),
|
|
56
|
+
response: z.string().openapi({ description: 'Test response' }),
|
|
57
|
+
},
|
|
58
|
+
handler: async () => Promise.resolve('success'),
|
|
59
|
+
});
|
|
60
|
+
defaultApi.addRoute(route);
|
|
61
|
+
const happyReq = TestUtils.createRequest('/api/route', Method.POST, { name: 'king' });
|
|
62
|
+
const happyRes = await defaultApi.processRootRoute(happyReq);
|
|
63
|
+
expect(happyRes.body, 'Should return normal response if body is valid').toBe('success');
|
|
64
|
+
expect(happyRes.status, 'Should return status 200 on normal response').toBe(200);
|
|
65
|
+
const req = TestUtils.createRequest('/api/route', Method.POST);
|
|
66
|
+
const res = await defaultApi.processRootRoute(req);
|
|
67
|
+
expect(res.body, 'Should return unknown error if error happens').toEqual({
|
|
68
|
+
error: {
|
|
69
|
+
code: ErrorCode.ValidationFailed,
|
|
70
|
+
fieldErrors: [
|
|
71
|
+
{
|
|
72
|
+
field: 'name',
|
|
73
|
+
message: 'Required',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
location: 'Body',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
expect(res.status, 'Should return status 400 on validation error').toEqual(400);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ErrorCode } from '../../../enums/ErrorCode
|
|
2
|
-
import { ErrorConfigMap } from '../../../types/config/ErrorConfigMap
|
|
1
|
+
import { ErrorCode } from '../../../enums/ErrorCode';
|
|
2
|
+
import { ErrorConfigMap } from '../../../types/config/ErrorConfigMap';
|
|
3
3
|
export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
4
4
|
[ErrorCode.UnknownError]: {
|
|
5
5
|
readonly status: "500";
|
|
@@ -47,7 +47,7 @@ export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
|
47
47
|
field: string;
|
|
48
48
|
}[] | undefined;
|
|
49
49
|
}>, "many">;
|
|
50
|
-
location: import("zod").ZodNativeEnum<typeof import("
|
|
50
|
+
location: import("zod").ZodNativeEnum<typeof import("../../..").OpenApiValidationLocation>;
|
|
51
51
|
}, "strip", import("zod").ZodTypeAny, {
|
|
52
52
|
code: ErrorCode.ValidationFailed;
|
|
53
53
|
fieldErrors: {
|
|
@@ -58,7 +58,7 @@ export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
|
58
58
|
field: string;
|
|
59
59
|
}[] | undefined;
|
|
60
60
|
}[];
|
|
61
|
-
location: import("
|
|
61
|
+
location: import("../../..").OpenApiValidationLocation;
|
|
62
62
|
}, {
|
|
63
63
|
code: ErrorCode.ValidationFailed;
|
|
64
64
|
fieldErrors: {
|
|
@@ -69,7 +69,7 @@ export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
|
69
69
|
field: string;
|
|
70
70
|
}[] | undefined;
|
|
71
71
|
}[];
|
|
72
|
-
location: import("
|
|
72
|
+
location: import("../../..").OpenApiValidationLocation;
|
|
73
73
|
}>;
|
|
74
74
|
}, "strip", import("zod").ZodTypeAny, {
|
|
75
75
|
error: {
|
|
@@ -82,7 +82,7 @@ export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
|
82
82
|
field: string;
|
|
83
83
|
}[] | undefined;
|
|
84
84
|
}[];
|
|
85
|
-
location: import("
|
|
85
|
+
location: import("../../..").OpenApiValidationLocation;
|
|
86
86
|
};
|
|
87
87
|
}, {
|
|
88
88
|
error: {
|
|
@@ -95,7 +95,7 @@ export declare class DefaultErrorMap implements ErrorConfigMap<ErrorCode> {
|
|
|
95
95
|
field: string;
|
|
96
96
|
}[] | undefined;
|
|
97
97
|
}[];
|
|
98
|
-
location: import("
|
|
98
|
+
location: import("../../..").OpenApiValidationLocation;
|
|
99
99
|
};
|
|
100
100
|
}>;
|
|
101
101
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ErrorCode } from '../../../enums/ErrorCode
|
|
2
|
-
import { unknownErrorResponseValidator } from '../../../types/errors/responses/UnknownErrorResponse
|
|
3
|
-
import { validationErrorResponseValidator } from '../../../types/errors/responses/ValidationErrorResponse
|
|
4
|
-
import { notFoundErrorResponseValidator } from '../../../types/errors/responses/NotFoundErrorResponse
|
|
1
|
+
import { ErrorCode } from '../../../enums/ErrorCode';
|
|
2
|
+
import { unknownErrorResponseValidator } from '../../../types/errors/responses/UnknownErrorResponse';
|
|
3
|
+
import { validationErrorResponseValidator } from '../../../types/errors/responses/ValidationErrorResponse';
|
|
4
|
+
import { notFoundErrorResponseValidator } from '../../../types/errors/responses/NotFoundErrorResponse';
|
|
5
5
|
export class DefaultErrorMap {
|
|
6
6
|
[ErrorCode.UnknownError] = {
|
|
7
7
|
status: '500',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SampleRouteType } from '../../../enums/SampleRouteType
|
|
2
|
-
import { RouteContextMap } from '../../../types/config/RouteContextMap
|
|
3
|
-
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap
|
|
1
|
+
import { SampleRouteType } from '../../../enums/SampleRouteType';
|
|
2
|
+
import { RouteContextMap } from '../../../types/config/RouteContextMap';
|
|
3
|
+
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap';
|
|
4
4
|
export declare class DefaultRouteContextMap implements RouteContextMap<SampleRouteType, DefaultRouteParamsMap> {
|
|
5
5
|
Public: () => Promise<{}>;
|
|
6
6
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { SampleRouteType } from '../../../enums/SampleRouteType
|
|
2
|
-
import { RouteConfigMap } from '../../../types/config/RouteConfigMap
|
|
3
|
-
import { ErrorCode } from '../../../enums/ErrorCode
|
|
4
|
-
import { DefaultRouteContextMap } from './DefaultRouteContextMap
|
|
5
|
-
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap
|
|
1
|
+
import { SampleRouteType } from '../../../enums/SampleRouteType';
|
|
2
|
+
import { RouteConfigMap } from '../../../types/config/RouteConfigMap';
|
|
3
|
+
import { ErrorCode } from '../../../enums/ErrorCode';
|
|
4
|
+
import { DefaultRouteContextMap } from './DefaultRouteContextMap';
|
|
5
|
+
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap';
|
|
6
6
|
export declare class DefaultRouteMap implements RouteConfigMap<SampleRouteType, ErrorCode, DefaultRouteParamsMap, DefaultRouteContextMap> {
|
|
7
7
|
Public: {
|
|
8
8
|
readonly authorization: false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DefaultRouteContextMap } from './DefaultRouteContextMap
|
|
2
|
-
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap
|
|
1
|
+
import { DefaultRouteContextMap } from './DefaultRouteContextMap';
|
|
2
|
+
import { DefaultRouteParamsMap } from './DefaultRouteParamsMap';
|
|
3
3
|
export class DefaultRouteMap {
|
|
4
4
|
Public = {
|
|
5
5
|
authorization: false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SampleRouteType } from '../../../enums/SampleRouteType
|
|
2
|
-
import { RouteExtraPropsMap } from '../../../types/config/RouteExtraPropsMap
|
|
1
|
+
import { SampleRouteType } from '../../../enums/SampleRouteType';
|
|
2
|
+
import { RouteExtraPropsMap } from '../../../types/config/RouteExtraPropsMap';
|
|
3
3
|
export declare class DefaultRouteParamsMap implements RouteExtraPropsMap<SampleRouteType> {
|
|
4
4
|
Public: undefined;
|
|
5
5
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { OpenApi } from '../../../OpenApi
|
|
1
|
+
import { OpenApi } from '../../../OpenApi';
|
|
2
2
|
export type OpenApiConstructor = (conf: any) => OpenApi<any, any, any>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ZodTypeAny, ZodRawShape } from 'zod';
|
|
2
|
-
import { AnyRoute } from '../../types/AnyRoute
|
|
3
|
-
import { ValidationUtils } from '../ValidationUtils/ValidationUtils
|
|
2
|
+
import { AnyRoute } from '../../types/AnyRoute';
|
|
3
|
+
import { ValidationUtils } from '../ValidationUtils/ValidationUtils';
|
|
4
4
|
interface DescriptionCheckerConfig {
|
|
5
5
|
checkValidators: boolean;
|
|
6
6
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe } from 'node:test';
|
|
2
|
+
import { expect, test } from 'vitest';
|
|
3
|
+
import { TestUtils } from '../TestUtils/TestUtils';
|
|
4
|
+
import { SampleRouteType } from '../../enums/SampleRouteType';
|
|
5
|
+
import { Method } from '../../enums/Methods';
|
|
6
|
+
import z from 'zod';
|
|
7
|
+
describe('DescriptionChecker', () => {
|
|
8
|
+
test('Checks route descriptions', async ({ expect }) => {
|
|
9
|
+
const api = TestUtils.createOpenApi();
|
|
10
|
+
const route = api.factory.createRoute({
|
|
11
|
+
type: SampleRouteType.Public,
|
|
12
|
+
method: Method.GET,
|
|
13
|
+
path: '/something',
|
|
14
|
+
description: '',
|
|
15
|
+
validators: {
|
|
16
|
+
response: z.string().openapi({ description: 'Testing' }),
|
|
17
|
+
},
|
|
18
|
+
handler: () => Promise.resolve('Something'),
|
|
19
|
+
});
|
|
20
|
+
expect(() => {
|
|
21
|
+
api.addRoute(route);
|
|
22
|
+
}).toThrowError(new Error('Description for /something is missing or too small'));
|
|
23
|
+
route.description = 'Testing route description';
|
|
24
|
+
expect(() => {
|
|
25
|
+
api.addRoute(route);
|
|
26
|
+
}).not.toThrowError();
|
|
27
|
+
});
|
|
28
|
+
test('Checks response validator descriptions', async ({ expect }) => {
|
|
29
|
+
const api = TestUtils.createOpenApi();
|
|
30
|
+
const route = api.factory.createRoute({
|
|
31
|
+
type: SampleRouteType.Public,
|
|
32
|
+
method: Method.GET,
|
|
33
|
+
path: '/something',
|
|
34
|
+
description: 'Testing route description',
|
|
35
|
+
validators: {
|
|
36
|
+
response: z.string(),
|
|
37
|
+
},
|
|
38
|
+
handler: () => Promise.resolve('Something'),
|
|
39
|
+
});
|
|
40
|
+
expect(() => {
|
|
41
|
+
api.addRoute(route);
|
|
42
|
+
}).toThrowError(new Error("Route 'GET:/something': responseValidator missing openapi description on field 'responseValidator'"));
|
|
43
|
+
route.validators.response = route.validators.response.openapi({ description: 'Something useful' });
|
|
44
|
+
expect(() => {
|
|
45
|
+
api.addRoute(route);
|
|
46
|
+
}).not.toThrowError();
|
|
47
|
+
});
|
|
48
|
+
test('Checks body validator descriptions', async ({ expect }) => {
|
|
49
|
+
const api = TestUtils.createOpenApi();
|
|
50
|
+
const route = api.factory.createRoute({
|
|
51
|
+
type: SampleRouteType.Public,
|
|
52
|
+
method: Method.POST,
|
|
53
|
+
path: '/something',
|
|
54
|
+
description: 'Testing route description',
|
|
55
|
+
validators: {
|
|
56
|
+
response: z.string().openapi({ description: 'Test description' }),
|
|
57
|
+
body: z.object({
|
|
58
|
+
name: z.string(),
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
handler: () => Promise.resolve('Something'),
|
|
62
|
+
});
|
|
63
|
+
expect(() => {
|
|
64
|
+
api.addRoute(route);
|
|
65
|
+
}).toThrowError(new Error("Route 'POST:/something': bodyValidator missing openapi description on field 'name'"));
|
|
66
|
+
const route2 = api.factory.createRoute({
|
|
67
|
+
type: SampleRouteType.Public,
|
|
68
|
+
method: Method.POST,
|
|
69
|
+
path: '/something',
|
|
70
|
+
description: 'Testing route description',
|
|
71
|
+
validators: {
|
|
72
|
+
response: z.string().openapi({ description: 'Test description' }),
|
|
73
|
+
body: z.object({
|
|
74
|
+
name: z.string().openapi({ description: 'Name' }),
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
handler: () => Promise.resolve('Something'),
|
|
78
|
+
});
|
|
79
|
+
expect(() => {
|
|
80
|
+
api.addRoute(route2);
|
|
81
|
+
}).not.toThrowError();
|
|
82
|
+
});
|
|
83
|
+
test('Checks validator descriptions in array items', async () => {
|
|
84
|
+
const api = TestUtils.createOpenApi();
|
|
85
|
+
const route = api.factory.createRoute({
|
|
86
|
+
type: SampleRouteType.Public,
|
|
87
|
+
method: Method.POST,
|
|
88
|
+
path: '/something',
|
|
89
|
+
description: 'Testing route description',
|
|
90
|
+
validators: {
|
|
91
|
+
response: z.object({
|
|
92
|
+
items: z.array(z.object({
|
|
93
|
+
name: z.string(),
|
|
94
|
+
})).openapi({ description: 'Items of array' }),
|
|
95
|
+
}).openapi({ description: 'Test response' }),
|
|
96
|
+
},
|
|
97
|
+
handler: () => Promise.resolve({ items: [{ name: 'Something' }] }),
|
|
98
|
+
});
|
|
99
|
+
expect(() => {
|
|
100
|
+
api.addRoute(route);
|
|
101
|
+
}).toThrowError(new Error("Route 'POST:/something': responseValidator missing openapi description on field 'name'"));
|
|
102
|
+
const route2 = api.factory.createRoute({
|
|
103
|
+
type: SampleRouteType.Public,
|
|
104
|
+
method: Method.POST,
|
|
105
|
+
path: '/something',
|
|
106
|
+
description: 'Testing route description',
|
|
107
|
+
validators: {
|
|
108
|
+
response: z.object({
|
|
109
|
+
items: z.array(z.object({
|
|
110
|
+
name: z.string().openapi({ description: 'Name of item' }),
|
|
111
|
+
})).openapi({ description: 'Items of array' }),
|
|
112
|
+
}).openapi({ description: 'Test response' }),
|
|
113
|
+
},
|
|
114
|
+
handler: () => Promise.resolve({ items: [{ name: 'Something' }] }),
|
|
115
|
+
});
|
|
116
|
+
expect(() => {
|
|
117
|
+
api.addRoute(route2);
|
|
118
|
+
}).not.toThrowError();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { expect, test } from 'vitest';
|
|
2
|
+
import { DevelopmentUtils } from './DevelopmentUtils';
|
|
3
|
+
import { describe } from 'node:test';
|
|
4
|
+
describe('Development Utils', () => {
|
|
5
|
+
test('Swagger HTML returned correctly', () => {
|
|
6
|
+
const utils = new DevelopmentUtils();
|
|
7
|
+
const html = utils.getSwaggerHTML('/test');
|
|
8
|
+
expect(html).toContain('SwaggerUIBundle');
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ExpressApp } from './types/ExpressApp
|
|
2
|
-
import { DevelopmentUtils } from '../DevelopmentUtils/DevelopmentUtils
|
|
3
|
-
import { OpenApi } from '../../OpenApi
|
|
4
|
-
import { AnyConfig } from '../../types/config/AnyConfig
|
|
5
|
-
import { RoutePath } from '../../types/RoutePath
|
|
1
|
+
import { ExpressApp } from './types/ExpressApp';
|
|
2
|
+
import { DevelopmentUtils } from '../DevelopmentUtils/DevelopmentUtils';
|
|
3
|
+
import { OpenApi } from '../../OpenApi';
|
|
4
|
+
import { AnyConfig } from '../../types/config/AnyConfig';
|
|
5
|
+
import { RoutePath } from '../../types/RoutePath';
|
|
6
6
|
export declare class ExpressWrapper<TRouteTypes extends string, TErrorCodes extends string, TConfig extends AnyConfig<TRouteTypes, TErrorCodes>> {
|
|
7
7
|
protected service: OpenApi<TRouteTypes, TErrorCodes, TConfig>;
|
|
8
8
|
protected developmentUtils: DevelopmentUtils;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import supertest from 'supertest';
|
|
4
|
+
import { TestUtils } from '../TestUtils/TestUtils';
|
|
5
|
+
import { ErrorCode } from '../../enums/ErrorCode';
|
|
6
|
+
import z from 'zod';
|
|
7
|
+
import { Method } from '../../enums/Methods';
|
|
8
|
+
import { SampleRouteType } from '../../enums/SampleRouteType';
|
|
9
|
+
import { OpenApi } from '../../OpenApi';
|
|
10
|
+
describe('ExpressWrapper', () => {
|
|
11
|
+
test('Can mount the api correctly', async () => {
|
|
12
|
+
const api = TestUtils.createOpenApi();
|
|
13
|
+
const app = express();
|
|
14
|
+
api.wrappers.express.createOpenApiRootRoute(app);
|
|
15
|
+
const errResponse = await supertest(app).get('/api');
|
|
16
|
+
expect(errResponse.status, 'Should be 404 on unknown route').toBe(404);
|
|
17
|
+
expect(errResponse.body, 'Should be error on unknown route').toEqual({ error: ErrorCode.NotFound });
|
|
18
|
+
const goodResponse = await supertest(app).get('/api/sample');
|
|
19
|
+
expect(goodResponse.status, 'Should be 200 on sample route').toBe(200);
|
|
20
|
+
expect(goodResponse.body, "Should be body 'success'").toEqual('success');
|
|
21
|
+
});
|
|
22
|
+
test('Can mount swagger routes correctly', async () => {
|
|
23
|
+
const api = TestUtils.createOpenApi();
|
|
24
|
+
const app = express();
|
|
25
|
+
api.wrappers.express.createSwaggerRoute('/swagger', app);
|
|
26
|
+
const goodResponse = await supertest(app).get('/swagger');
|
|
27
|
+
expect(goodResponse.status, 'Should be 200 on swagger route').toBe(200);
|
|
28
|
+
expect(goodResponse.text, 'Swagger UI pieces should be in HTML').toContain('swagger-ui');
|
|
29
|
+
expect(goodResponse.text, 'Default schema path should be present').toContain('/openapi-schema');
|
|
30
|
+
});
|
|
31
|
+
test('Can mount stoplight routes correctly', async () => {
|
|
32
|
+
const api = TestUtils.createOpenApi();
|
|
33
|
+
const app = express();
|
|
34
|
+
api.wrappers.express.createStoplightRoute('/light', app);
|
|
35
|
+
const goodResponse = await supertest(app).get('/light');
|
|
36
|
+
expect(goodResponse.status, 'Should be 200 on stoplight route').toBe(200);
|
|
37
|
+
expect(goodResponse.text, 'Stoplight UI pieces should be in HTML').toContain('@stoplight');
|
|
38
|
+
expect(goodResponse.text, 'Default schema path should be present').toContain('/openapi-schema');
|
|
39
|
+
});
|
|
40
|
+
test('Can mount schema routes correctly', async () => {
|
|
41
|
+
const api = TestUtils.createOpenApi();
|
|
42
|
+
const app = express();
|
|
43
|
+
api.wrappers.express.createSchemaRoute('/schema', app);
|
|
44
|
+
const goodResponse = await supertest(app).get('/schema');
|
|
45
|
+
expect(goodResponse.status, 'Should be 200 on schema route').toBe(200);
|
|
46
|
+
expect(goodResponse.text, 'Response should contain pieces of openapi schema').toContain('Sample route');
|
|
47
|
+
});
|
|
48
|
+
test('Can mount stoplight routes correctly', async () => {
|
|
49
|
+
const api = TestUtils.createOpenApi();
|
|
50
|
+
const app = express();
|
|
51
|
+
api.wrappers.express.createStoplightRoute('/light', app);
|
|
52
|
+
const goodResponse = await supertest(app).get('/light');
|
|
53
|
+
expect(goodResponse.status, 'Should be 200 on stoplight route').toBe(200);
|
|
54
|
+
expect(goodResponse.text, 'Stoplight UI pieces should be in HTML').toContain('@stoplight');
|
|
55
|
+
expect(goodResponse.text, 'Default schema path should be present').toContain('/openapi-schema');
|
|
56
|
+
});
|
|
57
|
+
test('Works correctly with array header values', async () => {
|
|
58
|
+
class ExpressAppMock {
|
|
59
|
+
handler;
|
|
60
|
+
post(route, handler) {
|
|
61
|
+
this.handler = handler;
|
|
62
|
+
}
|
|
63
|
+
;
|
|
64
|
+
get = () => { };
|
|
65
|
+
delete = () => { };
|
|
66
|
+
put = () => { };
|
|
67
|
+
patch = () => { };
|
|
68
|
+
async test(req) {
|
|
69
|
+
let body;
|
|
70
|
+
let status = 0;
|
|
71
|
+
const res = {
|
|
72
|
+
header: function () {
|
|
73
|
+
return this;
|
|
74
|
+
},
|
|
75
|
+
status: function (code) {
|
|
76
|
+
status = code;
|
|
77
|
+
return this;
|
|
78
|
+
},
|
|
79
|
+
json: function (data) {
|
|
80
|
+
body = data;
|
|
81
|
+
return this;
|
|
82
|
+
},
|
|
83
|
+
send: function () {
|
|
84
|
+
return this;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
if (!this.handler) {
|
|
88
|
+
throw new Error("Handler wasn't set");
|
|
89
|
+
}
|
|
90
|
+
await this.handler(req, res);
|
|
91
|
+
return { status, body };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
;
|
|
95
|
+
const appMock = new ExpressAppMock();
|
|
96
|
+
const api = OpenApi.builder
|
|
97
|
+
.customizeRoutes(SampleRouteType)
|
|
98
|
+
.defineRouteContexts({
|
|
99
|
+
[SampleRouteType.Public]: (ctx) => Promise.resolve({
|
|
100
|
+
authorization: ctx.request.headers.get('Authorization'),
|
|
101
|
+
}),
|
|
102
|
+
})
|
|
103
|
+
.defineRoutes({
|
|
104
|
+
[SampleRouteType.Public]: {
|
|
105
|
+
authorization: true,
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
.create();
|
|
109
|
+
api.wrappers.express.createOpenApiRootRoute(appMock);
|
|
110
|
+
const route = api.factory.createRoute({
|
|
111
|
+
type: SampleRouteType.Public,
|
|
112
|
+
method: Method.POST,
|
|
113
|
+
path: '/test-multi-headers',
|
|
114
|
+
description: 'Multiheader test route',
|
|
115
|
+
validators: {
|
|
116
|
+
response: z.unknown().nullable().openapi({ description: 'Authorization header' }),
|
|
117
|
+
},
|
|
118
|
+
handler: (ctx) => Promise.resolve(ctx.authorization),
|
|
119
|
+
});
|
|
120
|
+
api.addRoute(route);
|
|
121
|
+
const req = {
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: ['Bearer1', 'Bearer2'],
|
|
124
|
+
ContentType: undefined,
|
|
125
|
+
},
|
|
126
|
+
body: '',
|
|
127
|
+
method: 'POST',
|
|
128
|
+
protocol: '',
|
|
129
|
+
originalUrl: '/api/test-multi-headers',
|
|
130
|
+
host: 'http://localhost',
|
|
131
|
+
};
|
|
132
|
+
const goodResponse = await appMock.test(req);
|
|
133
|
+
expect(goodResponse.status, 'Should be 200 on sample route').toBe(200);
|
|
134
|
+
expect(goodResponse.body, 'Route should return both headers').toBe('Bearer1,Bearer2');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { ExpressRequest } from './ExpressRequest
|
|
2
|
-
import { ExpressResponse } from './ExpressResponse
|
|
1
|
+
import { ExpressRequest } from './ExpressRequest';
|
|
2
|
+
import { ExpressResponse } from './ExpressResponse';
|
|
3
3
|
export type ExpressHandler = (req: ExpressRequest, res: ExpressResponse) => void | Promise<void>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { LogLevel } from './types/LogLevel
|
|
1
|
+
import { LogLevel } from './types/LogLevel';
|
|
2
2
|
export declare class Logger {
|
|
3
3
|
protected invoker: string;
|
|
4
4
|
static logLevel: LogLevel;
|
|
5
5
|
static showTime: boolean;
|
|
6
6
|
constructor(invoker: string, originalInvoker?: string);
|
|
7
|
+
derrive(invoker: string): Logger;
|
|
7
8
|
info(message: string, data?: Record<string, unknown>): void;
|
|
8
9
|
debug(message: string, data?: object): void;
|
|
9
10
|
error(message: string | null, error: unknown, data?: object): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LogLevel } from './types/LogLevel
|
|
1
|
+
import { LogLevel } from './types/LogLevel';
|
|
2
2
|
export class Logger {
|
|
3
3
|
invoker;
|
|
4
4
|
static logLevel = LogLevel.all;
|
|
@@ -6,6 +6,9 @@ export class Logger {
|
|
|
6
6
|
constructor(invoker, originalInvoker) {
|
|
7
7
|
this.invoker = (originalInvoker ? `${originalInvoker}:` : '') + invoker;
|
|
8
8
|
}
|
|
9
|
+
derrive(invoker) {
|
|
10
|
+
return new Logger(invoker, this.invoker);
|
|
11
|
+
}
|
|
9
12
|
info(message, data) {
|
|
10
13
|
if (Logger.logLevel === LogLevel.error) {
|
|
11
14
|
return;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|