@furystack/rest-service 6.2.7 → 6.2.9
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/dist/api-manager.js +22 -16
- package/dist/api-manager.js.map +1 -1
- package/dist/rest.integration.test.js +61 -0
- package/dist/rest.integration.test.js.map +1 -1
- package/package.json +10 -10
- package/src/api-manager.ts +48 -42
- package/src/rest.integration.test.ts +74 -0
- package/types/api-manager.d.ts +13 -12
- package/types/api-manager.d.ts.map +1 -1
- package/types/rest.integration.test.d.ts +32 -0
- package/types/rest.integration.test.d.ts.map +1 -1
package/dist/api-manager.js
CHANGED
|
@@ -32,15 +32,16 @@ let ApiManager = class ApiManager {
|
|
|
32
32
|
return Object.keys(api);
|
|
33
33
|
}
|
|
34
34
|
compileApi(api, root) {
|
|
35
|
+
const supportedMethods = this.getSuportedMethods(api);
|
|
35
36
|
const compiledApi = {};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
supportedMethods.forEach((method) => {
|
|
38
|
+
compiledApi[method] = [
|
|
39
|
+
...Object.entries(api[method]).map(([path, action]) => {
|
|
40
|
+
const fullPath = `/${utils_1.PathHelper.normalize(utils_1.PathHelper.joinPaths(root, path))}`;
|
|
41
|
+
const matcher = (0, path_to_regexp_1.match)(fullPath, { decode: decodeURIComponent });
|
|
42
|
+
return { method, fullPath, matcher, action: action };
|
|
43
|
+
}),
|
|
44
|
+
];
|
|
44
45
|
});
|
|
45
46
|
return compiledApi;
|
|
46
47
|
}
|
|
@@ -79,10 +80,20 @@ let ApiManager = class ApiManager {
|
|
|
79
80
|
: false;
|
|
80
81
|
}
|
|
81
82
|
getActionFromEndpoint(compiledEndpoint, fullUrl, method) {
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
let resolvedParams;
|
|
84
|
+
const action = compiledEndpoint[method]?.find((route) => {
|
|
85
|
+
const result = route.matcher(fullUrl.pathname);
|
|
86
|
+
if (result) {
|
|
87
|
+
resolvedParams = result.params;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
});
|
|
91
|
+
return (action && {
|
|
92
|
+
...action,
|
|
93
|
+
params: resolvedParams,
|
|
94
|
+
});
|
|
84
95
|
}
|
|
85
|
-
async executeAction({ injector, req, res, fullUrl, action,
|
|
96
|
+
async executeAction({ injector, req, res, fullUrl, action, deserializeQueryParams, params, }) {
|
|
86
97
|
await (0, utils_1.usingAsync)(injector.createChild(), async (i) => {
|
|
87
98
|
const utils = i.getInstance(utils_2.Utils);
|
|
88
99
|
const httpUserContext = i.getInstance(http_user_context_1.HttpUserContext);
|
|
@@ -100,11 +111,6 @@ let ApiManager = class ApiManager {
|
|
|
100
111
|
headers: req.headers,
|
|
101
112
|
getQuery: () => deserializeQueryParams ? deserializeQueryParams(fullUrl.search) : (0, rest_1.deserializeQueryString)(fullUrl.search),
|
|
102
113
|
getUrlParams: () => {
|
|
103
|
-
if (!req.url || !regex) {
|
|
104
|
-
throw new Error('Error parsing request parameters. Missing URL or RegExp.');
|
|
105
|
-
}
|
|
106
|
-
const matcher = (0, path_to_regexp_1.match)(fullPath, { decode: decodeURIComponent });
|
|
107
|
-
const { params } = matcher(fullUrl.pathname);
|
|
108
114
|
return params;
|
|
109
115
|
},
|
|
110
116
|
});
|
package/dist/api-manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-manager.js","sourceRoot":"","sources":["../src/api-manager.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,4CAAyD;AAEzD,0CAAwD;AAExD,8CAAwD;AAExD,qDAAgD;
|
|
1
|
+
{"version":3,"file":"api-manager.js","sourceRoot":"","sources":["../src/api-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,10 @@ const createEchoApiServer = async () => {
|
|
|
20
20
|
'/headers': async ({ headers }) => (0, request_action_implementation_1.JsonResult)({ headers }),
|
|
21
21
|
'/query': async ({ getQuery }) => (0, request_action_implementation_1.JsonResult)({ query: getQuery() }),
|
|
22
22
|
'/urlParams/:id': async ({ getUrlParams }) => (0, request_action_implementation_1.JsonResult)({ url: getUrlParams() }),
|
|
23
|
+
'/segment': async () => (0, request_action_implementation_1.JsonResult)({ name: 'segment' }),
|
|
24
|
+
'/segment/subsegment': async () => (0, request_action_implementation_1.JsonResult)({ name: 'segment-subsegment' }),
|
|
25
|
+
'/segment/:id/subsegment': async ({ getUrlParams }) => (0, request_action_implementation_1.JsonResult)({ url: { ...getUrlParams(), name: 'segment-subsegment' } }),
|
|
26
|
+
'/segment/:optionalId?/optionalSubsegment/': async ({ getUrlParams }) => (0, request_action_implementation_1.JsonResult)({ url: getUrlParams(), name: 'optional-id' }),
|
|
23
27
|
},
|
|
24
28
|
POST: {
|
|
25
29
|
'/body': async ({ getBody }) => (0, request_action_implementation_1.JsonResult)({ body: await getBody() }),
|
|
@@ -91,5 +95,62 @@ describe('REST Integration tests with FETCH client', () => {
|
|
|
91
95
|
expect(result.result.url.id).toEqual(value);
|
|
92
96
|
});
|
|
93
97
|
});
|
|
98
|
+
it('should execute a request for a segment', async () => {
|
|
99
|
+
await (0, utils_1.usingAsync)(await createEchoApiServer(), async ({ client }) => {
|
|
100
|
+
const result = await client({
|
|
101
|
+
method: 'GET',
|
|
102
|
+
action: '/segment',
|
|
103
|
+
});
|
|
104
|
+
expect(result.response.status).toBe(200);
|
|
105
|
+
expect(result.result.name).toEqual('segment');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
it('should execute a request for a subsegment', async () => {
|
|
109
|
+
await (0, utils_1.usingAsync)(await createEchoApiServer(), async ({ client }) => {
|
|
110
|
+
const result = await client({
|
|
111
|
+
method: 'GET',
|
|
112
|
+
action: '/segment/subsegment',
|
|
113
|
+
});
|
|
114
|
+
expect(result.response.status).toBe(200);
|
|
115
|
+
expect(result.result.name).toEqual('segment-subsegment');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it('should execute a request for a subsegment with URL parameters', async () => {
|
|
119
|
+
await (0, utils_1.usingAsync)(await createEchoApiServer(), async ({ client }) => {
|
|
120
|
+
const value = 'value4';
|
|
121
|
+
const result = await client({
|
|
122
|
+
method: 'GET',
|
|
123
|
+
action: '/segment/:id/subsegment',
|
|
124
|
+
url: {
|
|
125
|
+
id: value,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
expect(result.response.status).toBe(200);
|
|
129
|
+
expect(result.result.url.id).toEqual(value);
|
|
130
|
+
expect(result.result.url.name).toEqual('segment-subsegment');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
it('should evaluate optional parameters in the URL', async () => {
|
|
134
|
+
await (0, utils_1.usingAsync)(await createEchoApiServer(), async ({ client }) => {
|
|
135
|
+
const result = await client({
|
|
136
|
+
method: 'GET',
|
|
137
|
+
action: '/segment/:optionalId?/optionalSubsegment/',
|
|
138
|
+
url: {},
|
|
139
|
+
});
|
|
140
|
+
expect(result.response.status).toBe(200);
|
|
141
|
+
expect(result.result.url.optionalId).toBeUndefined();
|
|
142
|
+
expect(result.result.name).toEqual('optional-id');
|
|
143
|
+
const result2 = await client({
|
|
144
|
+
method: 'GET',
|
|
145
|
+
action: '/segment/:optionalId?/optionalSubsegment/',
|
|
146
|
+
url: {
|
|
147
|
+
optionalId: 'value',
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
expect(result2.response.status).toBe(200);
|
|
151
|
+
expect(result2.result.url.optionalId).toEqual('value');
|
|
152
|
+
expect(result2.result.name).toEqual('optional-id');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
94
155
|
});
|
|
95
156
|
//# sourceMappingURL=rest.integration.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.integration.test.js","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":";;AAAA,8CAA4C;AAE5C,oEAA2D;AAC3D,4CAA6C;AAC7C,mFAA4D;AAC5D,qBAAkB;AAClB,uCAA0C;
|
|
1
|
+
{"version":3,"file":"rest.integration.test.js","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/rest-service",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.9",
|
|
4
4
|
"description": "Repository implementation for FuryStack",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -29,21 +29,21 @@
|
|
|
29
29
|
},
|
|
30
30
|
"homepage": "https://github.com/furystack/furystack",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@furystack/core": "^11.2.
|
|
33
|
-
"@furystack/inject": "^7.1.
|
|
34
|
-
"@furystack/logging": "^3.1.
|
|
35
|
-
"@furystack/repository": "^6.1.
|
|
36
|
-
"@furystack/rest": "^4.1.
|
|
37
|
-
"@furystack/security": "^2.1.
|
|
38
|
-
"@furystack/utils": "^3.1.
|
|
32
|
+
"@furystack/core": "^11.2.3",
|
|
33
|
+
"@furystack/inject": "^7.1.5",
|
|
34
|
+
"@furystack/logging": "^3.1.5",
|
|
35
|
+
"@furystack/repository": "^6.1.5",
|
|
36
|
+
"@furystack/rest": "^4.1.7",
|
|
37
|
+
"@furystack/security": "^2.1.5",
|
|
38
|
+
"@furystack/utils": "^3.1.5",
|
|
39
39
|
"ajv": "^8.12.0",
|
|
40
40
|
"ajv-formats": "^2.1.1",
|
|
41
41
|
"path-to-regexp": "^6.2.1",
|
|
42
42
|
"semaphore-async-await": "^1.5.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@furystack/rest-client-fetch": "^4.1.
|
|
46
|
-
"@types/jest": "^29.2.
|
|
45
|
+
"@furystack/rest-client-fetch": "^4.1.7",
|
|
46
|
+
"@types/jest": "^29.2.6",
|
|
47
47
|
"@types/node": "^18.11.18"
|
|
48
48
|
},
|
|
49
49
|
"typings": "./types/index.d.ts",
|
package/src/api-manager.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { Disposable } from '@furystack/utils'
|
|
2
2
|
import { PathHelper, usingAsync } from '@furystack/utils'
|
|
3
|
-
import type { RestApi } from '@furystack/rest'
|
|
3
|
+
import type { Method, RestApi } from '@furystack/rest'
|
|
4
4
|
import { deserializeQueryString } from '@furystack/rest'
|
|
5
5
|
import type { Injector } from '@furystack/inject'
|
|
6
6
|
import { Injectable, Injected } from '@furystack/inject'
|
|
7
7
|
import type { OnRequest } from './server-manager'
|
|
8
8
|
import { ServerManager } from './server-manager'
|
|
9
|
-
import {
|
|
9
|
+
import type { MatchFunction } from 'path-to-regexp'
|
|
10
|
+
import { match } from 'path-to-regexp'
|
|
10
11
|
import { NotFoundAction } from './actions/not-found-action'
|
|
11
12
|
import type { CorsOptions } from './models/cors-options'
|
|
12
13
|
import { Utils } from './utils'
|
|
@@ -33,14 +34,19 @@ export interface ImplementApiOptions<T extends RestApi> {
|
|
|
33
34
|
deserializeQueryParams?: (param: string) => any
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
export type
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
export type NewCompiledApiEntry = {
|
|
38
|
+
method: Method
|
|
39
|
+
fullPath: string
|
|
40
|
+
matcher: MatchFunction
|
|
41
|
+
action: RequestAction<any>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type NewCompiledApi = {
|
|
45
|
+
[K in Method]?: NewCompiledApiEntry[]
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
export type OnRequestOptions = OnRequest & {
|
|
43
|
-
compiledApi:
|
|
49
|
+
compiledApi: NewCompiledApi
|
|
44
50
|
hostName?: string
|
|
45
51
|
port: number
|
|
46
52
|
rootApiPath: string
|
|
@@ -52,27 +58,28 @@ export type OnRequestOptions = OnRequest & {
|
|
|
52
58
|
|
|
53
59
|
@Injectable({ lifetime: 'singleton' })
|
|
54
60
|
export class ApiManager implements Disposable {
|
|
55
|
-
private readonly apis = new Map<string,
|
|
61
|
+
private readonly apis = new Map<string, NewCompiledApi>()
|
|
56
62
|
|
|
57
63
|
public dispose() {
|
|
58
64
|
this.apis.clear()
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
private getSuportedMethods
|
|
62
|
-
return Object.keys(api) as
|
|
67
|
+
private getSuportedMethods(api: RestApiImplementation<any>): Method[] {
|
|
68
|
+
return Object.keys(api) as Method[]
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
private compileApi<T extends RestApi>(api: RestApiImplementation<T>, root: string) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
const supportedMethods = this.getSuportedMethods(api)
|
|
73
|
+
|
|
74
|
+
const compiledApi: NewCompiledApi = {}
|
|
75
|
+
supportedMethods.forEach((method: Method) => {
|
|
76
|
+
compiledApi[method] = [
|
|
77
|
+
...Object.entries(api[method as keyof typeof api]).map(([path, action]) => {
|
|
78
|
+
const fullPath = `/${PathHelper.normalize(PathHelper.joinPaths(root, path))}`
|
|
79
|
+
const matcher = match(fullPath, { decode: decodeURIComponent })
|
|
80
|
+
return { method, fullPath, matcher, action: action as RequestAction<any> }
|
|
81
|
+
}),
|
|
82
|
+
]
|
|
76
83
|
})
|
|
77
84
|
return compiledApi
|
|
78
85
|
}
|
|
@@ -94,7 +101,7 @@ export class ApiManager implements Disposable {
|
|
|
94
101
|
shouldExec: (msg) =>
|
|
95
102
|
this.shouldExecRequest({
|
|
96
103
|
...msg,
|
|
97
|
-
method: msg.req.method?.toUpperCase(),
|
|
104
|
+
method: msg.req.method?.toUpperCase() as Method,
|
|
98
105
|
rootApiPath,
|
|
99
106
|
supportedMethods,
|
|
100
107
|
url: PathHelper.normalize(msg.req.url || ''),
|
|
@@ -115,10 +122,10 @@ export class ApiManager implements Disposable {
|
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
public shouldExecRequest(options: {
|
|
118
|
-
method?:
|
|
125
|
+
method?: Method
|
|
119
126
|
url?: string
|
|
120
127
|
rootApiPath: string
|
|
121
|
-
supportedMethods:
|
|
128
|
+
supportedMethods: Method[]
|
|
122
129
|
}): boolean {
|
|
123
130
|
return options.method &&
|
|
124
131
|
options.url &&
|
|
@@ -128,15 +135,21 @@ export class ApiManager implements Disposable {
|
|
|
128
135
|
: false
|
|
129
136
|
}
|
|
130
137
|
|
|
131
|
-
private getActionFromEndpoint(compiledEndpoint:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
private getActionFromEndpoint(compiledEndpoint: NewCompiledApi, fullUrl: URL, method: Method) {
|
|
139
|
+
let resolvedParams: any
|
|
140
|
+
const action = compiledEndpoint[method]?.find((route) => {
|
|
141
|
+
const result = route.matcher(fullUrl.pathname)
|
|
142
|
+
if (result) {
|
|
143
|
+
resolvedParams = result.params
|
|
144
|
+
}
|
|
145
|
+
return result
|
|
146
|
+
})
|
|
147
|
+
return (
|
|
148
|
+
action && {
|
|
149
|
+
...action,
|
|
150
|
+
params: resolvedParams,
|
|
151
|
+
}
|
|
152
|
+
)
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
private async executeAction({
|
|
@@ -145,14 +158,12 @@ export class ApiManager implements Disposable {
|
|
|
145
158
|
res,
|
|
146
159
|
fullUrl,
|
|
147
160
|
action,
|
|
148
|
-
regex,
|
|
149
|
-
fullPath,
|
|
150
161
|
deserializeQueryParams,
|
|
162
|
+
params,
|
|
151
163
|
}: OnRequestOptions & {
|
|
152
164
|
fullUrl: URL
|
|
153
165
|
action: RequestAction<{ body: {}; result: {}; query: {}; url: {}; headers: {} }>
|
|
154
|
-
|
|
155
|
-
fullPath: string
|
|
166
|
+
params: any
|
|
156
167
|
}) {
|
|
157
168
|
await usingAsync(injector.createChild(), async (i) => {
|
|
158
169
|
const utils = i.getInstance(Utils)
|
|
@@ -175,11 +186,6 @@ export class ApiManager implements Disposable {
|
|
|
175
186
|
getQuery: () =>
|
|
176
187
|
deserializeQueryParams ? deserializeQueryParams(fullUrl.search) : deserializeQueryString(fullUrl.search),
|
|
177
188
|
getUrlParams: () => {
|
|
178
|
-
if (!req.url || !regex) {
|
|
179
|
-
throw new Error('Error parsing request parameters. Missing URL or RegExp.')
|
|
180
|
-
}
|
|
181
|
-
const matcher = match(fullPath, { decode: decodeURIComponent })
|
|
182
|
-
const { params } = matcher(fullUrl.pathname) as any
|
|
183
189
|
return params
|
|
184
190
|
},
|
|
185
191
|
})
|
|
@@ -213,7 +219,7 @@ export class ApiManager implements Disposable {
|
|
|
213
219
|
return
|
|
214
220
|
}
|
|
215
221
|
|
|
216
|
-
const action = this.getActionFromEndpoint(options.compiledApi, fullUrl, options.req.method?.toUpperCase() as
|
|
222
|
+
const action = this.getActionFromEndpoint(options.compiledApi, fullUrl, options.req.method?.toUpperCase() as Method)
|
|
217
223
|
if (action) {
|
|
218
224
|
await this.executeAction({ ...options, ...action, fullUrl })
|
|
219
225
|
} else {
|
|
@@ -15,6 +15,13 @@ export interface EchoApi extends RestApi {
|
|
|
15
15
|
query: { someObject: { foo: string } }
|
|
16
16
|
result: { query: { someObject: { foo: string } } }
|
|
17
17
|
}
|
|
18
|
+
'/segment': { result: { name: 'segment' } }
|
|
19
|
+
'/segment/subsegment': { result: { name: 'segment-subsegment' } }
|
|
20
|
+
'/segment/:id/subsegment': { url: { id: string }; result: { url: { id: string; name: 'segment-subsegment' } } }
|
|
21
|
+
'/segment/:optionalId?/optionalSubsegment/': {
|
|
22
|
+
url: { optionalId?: string }
|
|
23
|
+
result: { url: { optionalId?: string }; name: 'optional-id' }
|
|
24
|
+
}
|
|
18
25
|
}
|
|
19
26
|
POST: {
|
|
20
27
|
'/body': { body: { foo: string; bar: number }; result: { body: { foo: string; bar: number } } }
|
|
@@ -35,6 +42,12 @@ const createEchoApiServer = async () => {
|
|
|
35
42
|
'/headers': async ({ headers }) => JsonResult({ headers }),
|
|
36
43
|
'/query': async ({ getQuery }) => JsonResult({ query: getQuery() }),
|
|
37
44
|
'/urlParams/:id': async ({ getUrlParams }) => JsonResult({ url: getUrlParams() }),
|
|
45
|
+
'/segment': async () => JsonResult({ name: 'segment' }),
|
|
46
|
+
'/segment/subsegment': async () => JsonResult({ name: 'segment-subsegment' }),
|
|
47
|
+
'/segment/:id/subsegment': async ({ getUrlParams }) =>
|
|
48
|
+
JsonResult({ url: { ...getUrlParams(), name: 'segment-subsegment' } }),
|
|
49
|
+
'/segment/:optionalId?/optionalSubsegment/': async ({ getUrlParams }) =>
|
|
50
|
+
JsonResult({ url: getUrlParams(), name: 'optional-id' }),
|
|
38
51
|
},
|
|
39
52
|
POST: {
|
|
40
53
|
'/body': async ({ getBody }) => JsonResult({ body: await getBody() }),
|
|
@@ -110,4 +123,65 @@ describe('REST Integration tests with FETCH client', () => {
|
|
|
110
123
|
expect(result.result.url.id).toEqual(value)
|
|
111
124
|
})
|
|
112
125
|
})
|
|
126
|
+
|
|
127
|
+
it('should execute a request for a segment', async () => {
|
|
128
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
129
|
+
const result = await client({
|
|
130
|
+
method: 'GET',
|
|
131
|
+
action: '/segment',
|
|
132
|
+
})
|
|
133
|
+
expect(result.response.status).toBe(200)
|
|
134
|
+
expect(result.result.name).toEqual('segment')
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('should execute a request for a subsegment', async () => {
|
|
139
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
140
|
+
const result = await client({
|
|
141
|
+
method: 'GET',
|
|
142
|
+
action: '/segment/subsegment',
|
|
143
|
+
})
|
|
144
|
+
expect(result.response.status).toBe(200)
|
|
145
|
+
expect(result.result.name).toEqual('segment-subsegment')
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('should execute a request for a subsegment with URL parameters', async () => {
|
|
150
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
151
|
+
const value = 'value4'
|
|
152
|
+
const result = await client({
|
|
153
|
+
method: 'GET',
|
|
154
|
+
action: '/segment/:id/subsegment',
|
|
155
|
+
url: {
|
|
156
|
+
id: value,
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
expect(result.response.status).toBe(200)
|
|
160
|
+
expect(result.result.url.id).toEqual(value)
|
|
161
|
+
expect(result.result.url.name).toEqual('segment-subsegment')
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
it('should evaluate optional parameters in the URL', async () => {
|
|
165
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
166
|
+
const result = await client({
|
|
167
|
+
method: 'GET',
|
|
168
|
+
action: '/segment/:optionalId?/optionalSubsegment/',
|
|
169
|
+
url: {},
|
|
170
|
+
})
|
|
171
|
+
expect(result.response.status).toBe(200)
|
|
172
|
+
expect(result.result.url.optionalId).toBeUndefined()
|
|
173
|
+
expect(result.result.name).toEqual('optional-id')
|
|
174
|
+
|
|
175
|
+
const result2 = await client({
|
|
176
|
+
method: 'GET',
|
|
177
|
+
action: '/segment/:optionalId?/optionalSubsegment/',
|
|
178
|
+
url: {
|
|
179
|
+
optionalId: 'value',
|
|
180
|
+
},
|
|
181
|
+
})
|
|
182
|
+
expect(result2.response.status).toBe(200)
|
|
183
|
+
expect(result2.result.url.optionalId).toEqual('value')
|
|
184
|
+
expect(result2.result.name).toEqual('optional-id')
|
|
185
|
+
})
|
|
186
|
+
})
|
|
113
187
|
})
|
package/types/api-manager.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Disposable } from '@furystack/utils';
|
|
2
|
-
import type { RestApi } from '@furystack/rest';
|
|
2
|
+
import type { Method, RestApi } from '@furystack/rest';
|
|
3
3
|
import type { Injector } from '@furystack/inject';
|
|
4
4
|
import type { OnRequest } from './server-manager';
|
|
5
|
+
import type { MatchFunction } from 'path-to-regexp';
|
|
5
6
|
import type { CorsOptions } from './models/cors-options';
|
|
6
7
|
import './server-response-extensions';
|
|
7
8
|
import type { RequestAction } from './request-action-implementation';
|
|
@@ -21,17 +22,17 @@ export interface ImplementApiOptions<T extends RestApi> {
|
|
|
21
22
|
cors?: CorsOptions;
|
|
22
23
|
deserializeQueryParams?: (param: string) => any;
|
|
23
24
|
}
|
|
24
|
-
export type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
export type NewCompiledApiEntry = {
|
|
26
|
+
method: Method;
|
|
27
|
+
fullPath: string;
|
|
28
|
+
matcher: MatchFunction;
|
|
29
|
+
action: RequestAction<any>;
|
|
30
|
+
};
|
|
31
|
+
export type NewCompiledApi = {
|
|
32
|
+
[K in Method]?: NewCompiledApiEntry[];
|
|
32
33
|
};
|
|
33
34
|
export type OnRequestOptions = OnRequest & {
|
|
34
|
-
compiledApi:
|
|
35
|
+
compiledApi: NewCompiledApi;
|
|
35
36
|
hostName?: string;
|
|
36
37
|
port: number;
|
|
37
38
|
rootApiPath: string;
|
|
@@ -47,10 +48,10 @@ export declare class ApiManager implements Disposable {
|
|
|
47
48
|
private compileApi;
|
|
48
49
|
addApi<T extends RestApi>({ api, hostName, port, root, cors, injector, deserializeQueryParams, }: ImplementApiOptions<T>): Promise<void>;
|
|
49
50
|
shouldExecRequest(options: {
|
|
50
|
-
method?:
|
|
51
|
+
method?: Method;
|
|
51
52
|
url?: string;
|
|
52
53
|
rootApiPath: string;
|
|
53
|
-
supportedMethods:
|
|
54
|
+
supportedMethods: Method[];
|
|
54
55
|
}): boolean;
|
|
55
56
|
private getActionFromEndpoint;
|
|
56
57
|
private executeAction;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-manager.d.ts","sourceRoot":"","sources":["../src/api-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"api-manager.d.ts","sourceRoot":"","sources":["../src/api-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGxD,OAAO,8BAA8B,CAAA;AAIrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAEpE,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,OAAO,IAAI;KACpD,OAAO,IAAI,MAAM,CAAC,GAAG;SACnB,IAAI,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,GAAG,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK;KACnH;CACF,CAAA;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,OAAO;IACpD,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAA;IAC7B,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAChD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,aAAa,CAAA;IACtB,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;KAC1B,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,mBAAmB,EAAE;CACtC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG;IACzC,WAAW,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAChD,CAAA;AAED,qBACa,UAAW,YAAW,UAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IAElD,OAAO;IAId,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,UAAU;IAgBL,MAAM,CAAC,CAAC,SAAS,OAAO,EAAE,EACrC,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,sBAAsB,GACvB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IA6BlB,iBAAiB,CAAC,OAAO,EAAE;QAChC,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;QACnB,gBAAgB,EAAE,MAAM,EAAE,CAAA;KAC3B,GAAG,OAAO;IASX,OAAO,CAAC,qBAAqB;YAiBf,aAAa;YAmDb,SAAS;IA2BvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;CAC/C"}
|
|
@@ -39,6 +39,38 @@ export interface EchoApi extends RestApi {
|
|
|
39
39
|
};
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
|
+
'/segment': {
|
|
43
|
+
result: {
|
|
44
|
+
name: 'segment';
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
'/segment/subsegment': {
|
|
48
|
+
result: {
|
|
49
|
+
name: 'segment-subsegment';
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
'/segment/:id/subsegment': {
|
|
53
|
+
url: {
|
|
54
|
+
id: string;
|
|
55
|
+
};
|
|
56
|
+
result: {
|
|
57
|
+
url: {
|
|
58
|
+
id: string;
|
|
59
|
+
name: 'segment-subsegment';
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
'/segment/:optionalId?/optionalSubsegment/': {
|
|
64
|
+
url: {
|
|
65
|
+
optionalId?: string;
|
|
66
|
+
};
|
|
67
|
+
result: {
|
|
68
|
+
url: {
|
|
69
|
+
optionalId?: string;
|
|
70
|
+
};
|
|
71
|
+
name: 'optional-id';
|
|
72
|
+
};
|
|
73
|
+
};
|
|
42
74
|
};
|
|
43
75
|
POST: {
|
|
44
76
|
'/body': {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.integration.test.d.ts","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAI9C,OAAO,WAAW,CAAA;AAGlB,MAAM,WAAW,OAAQ,SAAQ,OAAO;IACtC,GAAG,EAAE;QACH,QAAQ,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAA;QAC7B,UAAU,EAAE;YAAE,OAAO,EAAE;gBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,OAAO,EAAE;oBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;QACpF,gBAAgB,EAAE;YAAE,GAAG,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,GAAG,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;QAC1E,QAAQ,EAAE;YACR,KAAK,EAAE;gBAAE,UAAU,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;YACtC,MAAM,EAAE;gBAAE,KAAK,EAAE;oBAAE,UAAU,EAAE;wBAAE,GAAG,EAAE,MAAM,CAAA;qBAAE,CAAA;iBAAE,CAAA;aAAE,CAAA;SACnD,CAAA;KACF,CAAA;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YAAE,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAC;oBAAC,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAChG,CAAA;CACF"}
|
|
1
|
+
{"version":3,"file":"rest.integration.test.d.ts","sourceRoot":"","sources":["../src/rest.integration.test.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAI9C,OAAO,WAAW,CAAA;AAGlB,MAAM,WAAW,OAAQ,SAAQ,OAAO;IACtC,GAAG,EAAE;QACH,QAAQ,EAAE;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAA;QAC7B,UAAU,EAAE;YAAE,OAAO,EAAE;gBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,OAAO,EAAE;oBAAE,KAAK,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;QACpF,gBAAgB,EAAE;YAAE,GAAG,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,GAAG,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;QAC1E,QAAQ,EAAE;YACR,KAAK,EAAE;gBAAE,UAAU,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;YACtC,MAAM,EAAE;gBAAE,KAAK,EAAE;oBAAE,UAAU,EAAE;wBAAE,GAAG,EAAE,MAAM,CAAA;qBAAE,CAAA;iBAAE,CAAA;aAAE,CAAA;SACnD,CAAA;QACD,UAAU,EAAE;YAAE,MAAM,EAAE;gBAAE,IAAI,EAAE,SAAS,CAAA;aAAE,CAAA;SAAE,CAAA;QAC3C,qBAAqB,EAAE;YAAE,MAAM,EAAE;gBAAE,IAAI,EAAE,oBAAoB,CAAA;aAAE,CAAA;SAAE,CAAA;QACjE,yBAAyB,EAAE;YAAE,GAAG,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,GAAG,EAAE;oBAAE,EAAE,EAAE,MAAM,CAAC;oBAAC,IAAI,EAAE,oBAAoB,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;QAC/G,2CAA2C,EAAE;YAC3C,GAAG,EAAE;gBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;YAC5B,MAAM,EAAE;gBAAE,GAAG,EAAE;oBAAE,UAAU,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAC;gBAAC,IAAI,EAAE,aAAa,CAAA;aAAE,CAAA;SAC9D,CAAA;KACF,CAAA;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YAAE,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,IAAI,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAC;oBAAC,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAA;KAChG,CAAA;CACF"}
|