@opra/core 0.33.13 → 1.0.0-alpha.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/cjs/augmentation/18n.augmentation.js +17 -4
- package/cjs/augmentation/http-controller.augmentation.js +25 -0
- package/cjs/constants.js +5 -0
- package/cjs/execution-context.js +25 -12
- package/cjs/{services → helpers}/logger.js +1 -2
- package/cjs/{services/api-service.js → helpers/service-base.js} +8 -8
- package/cjs/http/express-adapter.js +164 -0
- package/cjs/http/http-adapter.js +27 -0
- package/cjs/http/http-context.js +116 -0
- package/cjs/http/impl/asset-cache.js +21 -0
- package/cjs/http/impl/http-handler.js +575 -0
- package/cjs/http/{http-server-request.js → impl/http-incoming.host.js} +21 -46
- package/cjs/http/{http-server-response.js → impl/http-outgoing.host.js} +7 -26
- package/cjs/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +24 -22
- package/cjs/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +13 -54
- package/cjs/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +11 -14
- package/cjs/http/interfaces/http-incoming.interface.js +25 -0
- package/cjs/http/interfaces/http-outgoing.interface.js +22 -0
- package/cjs/http/interfaces/node-incoming-message.interface.js +63 -0
- package/cjs/http/interfaces/node-outgoing-message.interface.js +15 -0
- package/cjs/http/utils/body-reader.js +215 -0
- package/cjs/http/{helpers → utils}/convert-to-raw-headers.js +1 -2
- package/cjs/http/{helpers → utils}/match-known-fields.js +11 -9
- package/cjs/http/utils/wrap-exception.js +34 -0
- package/cjs/index.js +25 -25
- package/cjs/platform-adapter.js +21 -0
- package/cjs/type-guards.js +23 -0
- package/esm/augmentation/18n.augmentation.js +20 -7
- package/esm/augmentation/http-controller.augmentation.js +23 -0
- package/esm/constants.js +2 -0
- package/esm/execution-context.js +25 -13
- package/esm/{services → helpers}/logger.js +1 -2
- package/esm/{services/api-service.js → helpers/service-base.js} +6 -6
- package/esm/http/express-adapter.js +159 -0
- package/esm/http/http-adapter.js +23 -0
- package/esm/http/http-context.js +111 -0
- package/esm/http/impl/asset-cache.js +17 -0
- package/esm/http/impl/http-handler.js +570 -0
- package/esm/http/{http-server-request.js → impl/http-incoming.host.js} +17 -43
- package/esm/http/{http-server-response.js → impl/http-outgoing.host.js} +6 -26
- package/esm/http/{helpers/multipart-helper.js → impl/multipart-reader.js} +22 -20
- package/esm/http/impl/{http-incoming-message.host.js → node-incoming-message.host.js} +11 -52
- package/esm/http/impl/{http-outgoing-message.host.js → node-outgoing-message.host.js} +9 -12
- package/esm/http/interfaces/http-incoming.interface.js +22 -0
- package/esm/http/interfaces/http-outgoing.interface.js +19 -0
- package/esm/http/interfaces/node-incoming-message.interface.js +60 -0
- package/esm/http/interfaces/node-outgoing-message.interface.js +12 -0
- package/esm/http/utils/body-reader.js +210 -0
- package/esm/http/{helpers → utils}/convert-to-headers.js +1 -1
- package/esm/http/{helpers → utils}/convert-to-raw-headers.js +2 -3
- package/esm/http/{helpers → utils}/match-known-fields.js +11 -9
- package/esm/http/utils/wrap-exception.js +30 -0
- package/esm/index.js +25 -26
- package/esm/platform-adapter.js +19 -1
- package/esm/type-guards.js +16 -0
- package/package.json +22 -10
- package/types/augmentation/18n.augmentation.d.ts +32 -2
- package/types/augmentation/http-controller.augmentation.d.ts +21 -0
- package/types/constants.d.ts +2 -0
- package/types/execution-context.d.ts +24 -26
- package/types/helpers/service-base.d.ts +10 -0
- package/types/http/express-adapter.d.ts +13 -0
- package/types/http/http-adapter.d.ts +27 -0
- package/types/http/http-context.d.ts +44 -0
- package/types/http/impl/asset-cache.d.ts +5 -0
- package/types/http/impl/http-handler.d.ts +73 -0
- package/types/http/impl/http-incoming.host.d.ts +23 -0
- package/types/http/impl/http-outgoing.host.d.ts +17 -0
- package/types/http/{helpers/multipart-helper.d.ts → impl/multipart-reader.d.ts} +8 -6
- package/types/http/impl/{http-incoming-message.host.d.ts → node-incoming-message.host.d.ts} +9 -22
- package/types/http/impl/{http-outgoing-message.host.d.ts → node-outgoing-message.host.d.ts} +11 -27
- package/types/http/{http-server-request.d.ts → interfaces/http-incoming.interface.d.ts} +28 -17
- package/types/http/{http-server-response.d.ts → interfaces/http-outgoing.interface.d.ts} +17 -10
- package/types/http/interfaces/node-incoming-message.interface.d.ts +38 -0
- package/types/http/interfaces/node-outgoing-message.interface.d.ts +29 -0
- package/types/http/utils/body-reader.d.ts +41 -0
- package/types/http/utils/wrap-exception.d.ts +2 -0
- package/types/index.d.ts +24 -26
- package/types/platform-adapter.d.ts +20 -48
- package/types/type-guards.d.ts +8 -0
- package/cjs/augmentation/collection.augmentation.js +0 -2
- package/cjs/augmentation/container.augmentation.js +0 -2
- package/cjs/augmentation/resource.augmentation.js +0 -26
- package/cjs/augmentation/singleton.augmentation.js +0 -2
- package/cjs/augmentation/storage.augmentation.js +0 -2
- package/cjs/execution-context.host.js +0 -46
- package/cjs/http/adapters/express-adapter.host.js +0 -34
- package/cjs/http/adapters/express-adapter.js +0 -14
- package/cjs/http/adapters/node-http-adapter.host.js +0 -70
- package/cjs/http/adapters/node-http-adapter.js +0 -14
- package/cjs/http/helpers/json-body-loader.js +0 -29
- package/cjs/http/helpers/query-parsers.js +0 -16
- package/cjs/http/http-adapter-host.js +0 -715
- package/cjs/interfaces/interceptor.interface.js +0 -2
- package/cjs/interfaces/request-handler.interface.js +0 -2
- package/cjs/platform-adapter.host.js +0 -154
- package/cjs/request-context.js +0 -25
- package/cjs/request.host.js +0 -24
- package/cjs/request.js +0 -2
- package/cjs/response.host.js +0 -22
- package/cjs/response.js +0 -2
- package/esm/augmentation/collection.augmentation.js +0 -1
- package/esm/augmentation/container.augmentation.js +0 -1
- package/esm/augmentation/resource.augmentation.js +0 -24
- package/esm/augmentation/singleton.augmentation.js +0 -1
- package/esm/augmentation/storage.augmentation.js +0 -1
- package/esm/execution-context.host.js +0 -42
- package/esm/http/adapters/express-adapter.host.js +0 -30
- package/esm/http/adapters/express-adapter.js +0 -11
- package/esm/http/adapters/node-http-adapter.host.js +0 -65
- package/esm/http/adapters/node-http-adapter.js +0 -11
- package/esm/http/helpers/json-body-loader.js +0 -24
- package/esm/http/helpers/query-parsers.js +0 -12
- package/esm/http/http-adapter-host.js +0 -710
- package/esm/interfaces/interceptor.interface.js +0 -1
- package/esm/interfaces/request-handler.interface.js +0 -1
- package/esm/platform-adapter.host.js +0 -149
- package/esm/request-context.js +0 -22
- package/esm/request.host.js +0 -20
- package/esm/request.js +0 -1
- package/esm/response.host.js +0 -18
- package/esm/response.js +0 -1
- package/i18n/i18n/en/error.json +0 -21
- package/types/augmentation/collection.augmentation.d.ts +0 -146
- package/types/augmentation/container.augmentation.d.ts +0 -14
- package/types/augmentation/resource.augmentation.d.ts +0 -38
- package/types/augmentation/singleton.augmentation.d.ts +0 -83
- package/types/augmentation/storage.augmentation.d.ts +0 -50
- package/types/execution-context.host.d.ts +0 -25
- package/types/http/adapters/express-adapter.d.ts +0 -15
- package/types/http/adapters/express-adapter.host.d.ts +0 -12
- package/types/http/adapters/node-http-adapter.d.ts +0 -17
- package/types/http/adapters/node-http-adapter.host.d.ts +0 -19
- package/types/http/helpers/json-body-loader.d.ts +0 -5
- package/types/http/helpers/query-parsers.d.ts +0 -1
- package/types/http/http-adapter-host.d.ts +0 -34
- package/types/interfaces/interceptor.interface.d.ts +0 -2
- package/types/interfaces/request-handler.interface.d.ts +0 -4
- package/types/platform-adapter.host.d.ts +0 -43
- package/types/request-context.d.ts +0 -13
- package/types/request.d.ts +0 -14
- package/types/request.host.d.ts +0 -27
- package/types/response.d.ts +0 -22
- package/types/response.host.d.ts +0 -22
- package/types/services/api-service.d.ts +0 -10
- /package/cjs/http/{helpers → utils}/common.js +0 -0
- /package/cjs/http/{helpers → utils}/concat-readable.js +0 -0
- /package/cjs/http/{helpers → utils}/convert-to-headers.js +0 -0
- /package/esm/http/{helpers → utils}/common.js +0 -0
- /package/esm/http/{helpers → utils}/concat-readable.js +0 -0
- /package/types/{services → helpers}/logger.d.ts +0 -0
- /package/types/http/{helpers → utils}/common.d.ts +0 -0
- /package/types/http/{helpers → utils}/concat-readable.d.ts +0 -0
- /package/types/http/{helpers → utils}/convert-to-headers.d.ts +0 -0
- /package/types/http/{helpers → utils}/convert-to-raw-headers.d.ts +0 -0
- /package/types/http/{helpers → utils}/match-known-fields.d.ts +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import * as nodePath from 'path';
|
|
3
|
+
import { HttpApi, NotFoundError } from '@opra/common';
|
|
4
|
+
import { kHandler } from '../constants.js';
|
|
5
|
+
import { HttpAdapter } from './http-adapter.js';
|
|
6
|
+
import { HttpContext } from './http-context.js';
|
|
7
|
+
import { HttpIncoming } from './interfaces/http-incoming.interface.js';
|
|
8
|
+
import { HttpOutgoing } from './interfaces/http-outgoing.interface.js';
|
|
9
|
+
export class ExpressAdapter extends HttpAdapter {
|
|
10
|
+
constructor(app, document, options) {
|
|
11
|
+
super(document, options);
|
|
12
|
+
this._controllerInstances = new Map();
|
|
13
|
+
this.app = app;
|
|
14
|
+
if (!(this.document.api instanceof HttpApi))
|
|
15
|
+
throw new TypeError('document.api must be instance of HttpApi');
|
|
16
|
+
for (const c of this.api.controllers.values())
|
|
17
|
+
this._createControllers(c);
|
|
18
|
+
this._initRouter(options?.basePath);
|
|
19
|
+
}
|
|
20
|
+
get platform() {
|
|
21
|
+
return 'express';
|
|
22
|
+
}
|
|
23
|
+
async close() {
|
|
24
|
+
const processResource = async (resource) => {
|
|
25
|
+
if (resource.controllers.size) {
|
|
26
|
+
const subResources = Array.from(resource.controllers.values());
|
|
27
|
+
subResources.reverse();
|
|
28
|
+
for (const subResource of subResources) {
|
|
29
|
+
await processResource(subResource);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (resource.onShutdown) {
|
|
33
|
+
const instance = this._controllerInstances.get(resource) || resource.instance;
|
|
34
|
+
if (instance)
|
|
35
|
+
try {
|
|
36
|
+
await resource.onShutdown.call(instance, resource);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
this.logger.error(e);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
for (const c of this.api.controllers.values())
|
|
44
|
+
await processResource(c);
|
|
45
|
+
this._controllerInstances.clear();
|
|
46
|
+
}
|
|
47
|
+
getControllerInstance(controllerPath) {
|
|
48
|
+
const controller = this.api.findController(controllerPath);
|
|
49
|
+
return controller && this._controllerInstances.get(controller);
|
|
50
|
+
}
|
|
51
|
+
_initRouter(basePath) {
|
|
52
|
+
const router = Router();
|
|
53
|
+
if (basePath) {
|
|
54
|
+
if (!basePath.startsWith('/'))
|
|
55
|
+
basePath = '/' + basePath;
|
|
56
|
+
if (basePath)
|
|
57
|
+
this.app.use(basePath, router);
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
this.app.use(router);
|
|
61
|
+
const createContext = (_req, _res, args) => {
|
|
62
|
+
const request = HttpIncoming.from(_req);
|
|
63
|
+
const response = HttpOutgoing.from(_res);
|
|
64
|
+
const platformArgs = {
|
|
65
|
+
request: _req,
|
|
66
|
+
response: _res,
|
|
67
|
+
};
|
|
68
|
+
return new HttpContext({
|
|
69
|
+
adapter: this,
|
|
70
|
+
platform: this.platform,
|
|
71
|
+
platformArgs,
|
|
72
|
+
request,
|
|
73
|
+
response,
|
|
74
|
+
controller: args?.controller,
|
|
75
|
+
controllerInstance: args?.controllerInstance,
|
|
76
|
+
operation: args?.operation,
|
|
77
|
+
operationHandler: args?.operationHandler,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
/** Add an endpoint that returns document schema */
|
|
81
|
+
router.get('*', (_req, _res, next) => {
|
|
82
|
+
if (_req.url.includes('/$schema')) {
|
|
83
|
+
const url = (_req.url.includes('?') ? _req.url.substring(0, _req.url.indexOf('?')) : _req.url).toLowerCase();
|
|
84
|
+
if (url === '/$schema') {
|
|
85
|
+
const context = createContext(_req, _res);
|
|
86
|
+
this[kHandler].sendDocumentSchema(context).catch(next);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
next();
|
|
91
|
+
});
|
|
92
|
+
/** Add operation endpoints */
|
|
93
|
+
if (this.api.controllers.size) {
|
|
94
|
+
const processResource = (controller, currentPath) => {
|
|
95
|
+
currentPath = nodePath.join(currentPath, controller.path);
|
|
96
|
+
for (const operation of controller.operations.values()) {
|
|
97
|
+
const routePath = currentPath + (operation.path || '');
|
|
98
|
+
const controllerInstance = this._controllerInstances.get(controller);
|
|
99
|
+
const operationHandler = controllerInstance[operation.name];
|
|
100
|
+
if (!operationHandler)
|
|
101
|
+
continue;
|
|
102
|
+
/** Define router callback */
|
|
103
|
+
router[operation.method.toLowerCase()](routePath, (_req, _res, _next) => {
|
|
104
|
+
const context = createContext(_req, _res, {
|
|
105
|
+
controller,
|
|
106
|
+
controllerInstance,
|
|
107
|
+
operation,
|
|
108
|
+
operationHandler,
|
|
109
|
+
});
|
|
110
|
+
this[kHandler]
|
|
111
|
+
.handleRequest(context)
|
|
112
|
+
.then(() => {
|
|
113
|
+
if (!_res.headersSent)
|
|
114
|
+
_next();
|
|
115
|
+
})
|
|
116
|
+
.catch((e) => this.logger.fatal(e));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (controller.controllers.size) {
|
|
120
|
+
for (const child of controller.controllers.values())
|
|
121
|
+
processResource(child, currentPath);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
for (const c of this.api.controllers.values())
|
|
125
|
+
processResource(c, '/');
|
|
126
|
+
}
|
|
127
|
+
/** Add an endpoint that returns 404 error at last */
|
|
128
|
+
router.use('*', (_req, _res, next) => {
|
|
129
|
+
const res = HttpOutgoing.from(_res);
|
|
130
|
+
// const url = new URL(_req.originalUrl, '')
|
|
131
|
+
this[kHandler]
|
|
132
|
+
.sendErrorResponse(res, [
|
|
133
|
+
new NotFoundError({
|
|
134
|
+
message: `No endpoint found for [${_req.method}]${_req.baseUrl}`,
|
|
135
|
+
details: {
|
|
136
|
+
path: _req.baseUrl,
|
|
137
|
+
method: _req.method,
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
])
|
|
141
|
+
.catch(next);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
_createControllers(controller) {
|
|
145
|
+
let instance = controller.instance;
|
|
146
|
+
if (!instance && controller.ctor)
|
|
147
|
+
instance = new controller.ctor();
|
|
148
|
+
if (instance) {
|
|
149
|
+
if (typeof instance.onInit === 'function')
|
|
150
|
+
instance.onInit.call(instance, this);
|
|
151
|
+
this._controllerInstances.set(controller, instance);
|
|
152
|
+
// Initialize sub resources
|
|
153
|
+
for (const r of controller.controllers.values()) {
|
|
154
|
+
this._createControllers(r);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return instance;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HttpApi } from '@opra/common';
|
|
2
|
+
import { kHandler } from '../constants.js';
|
|
3
|
+
import { PlatformAdapter } from '../platform-adapter.js';
|
|
4
|
+
import { HttpHandler } from './impl/http-handler.js';
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @class HttpAdapter
|
|
8
|
+
*/
|
|
9
|
+
export class HttpAdapter extends PlatformAdapter {
|
|
10
|
+
constructor(document, options) {
|
|
11
|
+
super(document, options);
|
|
12
|
+
this.protocol = 'http';
|
|
13
|
+
if (!(document.api instanceof HttpApi))
|
|
14
|
+
throw new TypeError(`The document does not expose an HTTP Api`);
|
|
15
|
+
this[kHandler] = new HttpHandler(this);
|
|
16
|
+
this.interceptors = [...(options?.interceptors || [])];
|
|
17
|
+
if (options?.onRequest)
|
|
18
|
+
this.on('request', options.onRequest);
|
|
19
|
+
}
|
|
20
|
+
get api() {
|
|
21
|
+
return this.document.api;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { vg } from 'valgen';
|
|
2
|
+
import typeIs from '@browsery/type-is';
|
|
3
|
+
import { BadRequestError, InternalServerError, NotAcceptableError, } from '@opra/common';
|
|
4
|
+
import { kAssetCache } from '../constants.js';
|
|
5
|
+
import { ExecutionContext } from '../execution-context.js';
|
|
6
|
+
import { MultipartReader } from './impl/multipart-reader.js';
|
|
7
|
+
export class HttpContext extends ExecutionContext {
|
|
8
|
+
constructor(init) {
|
|
9
|
+
super({ ...init, document: init.adapter.document, protocol: 'http' });
|
|
10
|
+
this.adapter = init.adapter;
|
|
11
|
+
this.protocol = 'http';
|
|
12
|
+
if (init.controller)
|
|
13
|
+
this.controller = init.controller;
|
|
14
|
+
if (init.controllerInstance)
|
|
15
|
+
this.controllerInstance = init.controllerInstance;
|
|
16
|
+
if (init.operation)
|
|
17
|
+
this.operation = init.operation;
|
|
18
|
+
if (init.operationHandler)
|
|
19
|
+
this.operationHandler = init.operationHandler;
|
|
20
|
+
this.request = init.request;
|
|
21
|
+
this.response = init.response;
|
|
22
|
+
this.mediaType = init.mediaType;
|
|
23
|
+
this.cookies = init.cookies || {};
|
|
24
|
+
this.headers = init.headers || {};
|
|
25
|
+
this.pathParams = init.pathParams || {};
|
|
26
|
+
this.queryParams = init.queryParams || {};
|
|
27
|
+
this._body = init.body;
|
|
28
|
+
}
|
|
29
|
+
get isMultipart() {
|
|
30
|
+
return !!this.request.is('multipart');
|
|
31
|
+
}
|
|
32
|
+
async getMultipartReader() {
|
|
33
|
+
if (!this.isMultipart)
|
|
34
|
+
throw new InternalServerError('Request content is not a multipart content');
|
|
35
|
+
if (this._multipartReader)
|
|
36
|
+
return this._multipartReader;
|
|
37
|
+
const { request, mediaType } = this;
|
|
38
|
+
if (mediaType?.contentType) {
|
|
39
|
+
const arr = Array.isArray(mediaType.contentType) ? mediaType.contentType : [mediaType.contentType];
|
|
40
|
+
const contentType = arr.find(ct => typeIs.is(ct, ['multipart']));
|
|
41
|
+
if (!contentType)
|
|
42
|
+
throw new NotAcceptableError('This endpoint does not accept multipart requests');
|
|
43
|
+
}
|
|
44
|
+
const reader = new MultipartReader(request, {
|
|
45
|
+
maxFields: mediaType?.maxFields,
|
|
46
|
+
maxFieldsSize: mediaType?.maxFieldsSize,
|
|
47
|
+
maxFiles: mediaType?.maxFiles,
|
|
48
|
+
maxFileSize: mediaType?.maxFileSize,
|
|
49
|
+
maxTotalFileSize: mediaType?.maxTotalFileSize,
|
|
50
|
+
minFileSize: mediaType?.minFileSize,
|
|
51
|
+
});
|
|
52
|
+
this._multipartReader = reader;
|
|
53
|
+
return reader;
|
|
54
|
+
}
|
|
55
|
+
async getBody() {
|
|
56
|
+
if (this._body !== undefined)
|
|
57
|
+
return this._body;
|
|
58
|
+
const { request, operation, mediaType } = this;
|
|
59
|
+
if (this.isMultipart) {
|
|
60
|
+
const reader = await this.getMultipartReader();
|
|
61
|
+
/** Retrieve all fields */
|
|
62
|
+
const parts = await reader.getAll();
|
|
63
|
+
/** Filter fields according to configuration */
|
|
64
|
+
this._body = [];
|
|
65
|
+
const multipartFields = mediaType?.multipartFields;
|
|
66
|
+
if (mediaType && multipartFields?.length) {
|
|
67
|
+
const fieldsFound = new Map();
|
|
68
|
+
for (const item of parts) {
|
|
69
|
+
const field = mediaType.findMultipartField(item.fieldName, item.type);
|
|
70
|
+
if (field) {
|
|
71
|
+
fieldsFound.set(field, true);
|
|
72
|
+
this._body.push(item);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Check required fields */
|
|
76
|
+
for (const field of multipartFields) {
|
|
77
|
+
if (field.required && !fieldsFound.get(field))
|
|
78
|
+
throw new BadRequestError({
|
|
79
|
+
message: `Multipart field (${field.fieldName}) is required`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return this._body;
|
|
84
|
+
}
|
|
85
|
+
this._body = await this.request.readBody({ limit: operation.requestBody?.maxContentSize });
|
|
86
|
+
if (this._body != null) {
|
|
87
|
+
// Convert Buffer to string if media is text
|
|
88
|
+
if (Buffer.isBuffer(this._body) && request.is(['json', 'xml', 'txt', 'text']))
|
|
89
|
+
this._body = this._body.toString('utf-8');
|
|
90
|
+
// Transform text to Object if media is JSON
|
|
91
|
+
if (typeof this._body === 'string' && request.is(['json']))
|
|
92
|
+
this._body = JSON.parse(this._body);
|
|
93
|
+
}
|
|
94
|
+
if (mediaType) {
|
|
95
|
+
// Decode/Validate the data object according to data model
|
|
96
|
+
if (this._body && mediaType.type) {
|
|
97
|
+
let decode = this.adapter[kAssetCache].get(mediaType, 'decode');
|
|
98
|
+
if (!decode) {
|
|
99
|
+
decode =
|
|
100
|
+
mediaType.type?.generateCodec('decode', {
|
|
101
|
+
partial: operation.requestBody?.partial,
|
|
102
|
+
projection: '*',
|
|
103
|
+
}) || vg.isAny();
|
|
104
|
+
this.adapter[kAssetCache].set(mediaType, 'decode', decode);
|
|
105
|
+
}
|
|
106
|
+
this._body = decode(this._body);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return this._body;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class AssetCache {
|
|
2
|
+
constructor() {
|
|
3
|
+
this._items = new WeakMap();
|
|
4
|
+
}
|
|
5
|
+
get(obj, name) {
|
|
6
|
+
const cache = this._items.get(obj);
|
|
7
|
+
return cache && cache[name];
|
|
8
|
+
}
|
|
9
|
+
set(obj, name, asset) {
|
|
10
|
+
let cache = this._items.get(obj);
|
|
11
|
+
if (!cache) {
|
|
12
|
+
cache = {};
|
|
13
|
+
this._items.set(obj, cache);
|
|
14
|
+
}
|
|
15
|
+
cache[name] = asset;
|
|
16
|
+
}
|
|
17
|
+
}
|