@opra/core 0.25.4 → 0.26.0
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/http/adapters/express-adapter.host.js +34 -0
- package/cjs/{adapter/http → http/adapters}/express-adapter.js +1 -3
- package/cjs/{adapter/http/http-adapter.host.js → http/adapters/node-http-adapter.host.js} +30 -22
- package/cjs/http/adapters/node-http-adapter.js +14 -0
- package/cjs/http/helpers/json-body-loader.js +29 -0
- package/cjs/http/http-adapter-host.js +678 -0
- package/cjs/index.js +17 -16
- package/cjs/{adapter/platform-adapter.host.js → platform-adapter.host.js} +74 -45
- package/cjs/{adapter/endpoint-context.js → request-context.js} +5 -5
- package/cjs/{adapter/request.host.js → request.host.js} +3 -0
- package/cjs/response.js +2 -0
- package/esm/http/adapters/express-adapter.host.js +30 -0
- package/esm/{adapter/http → http/adapters}/express-adapter.js +1 -3
- package/esm/{adapter/http/http-adapter.host.js → http/adapters/node-http-adapter.host.js} +28 -20
- package/esm/http/adapters/node-http-adapter.js +11 -0
- package/esm/http/helpers/json-body-loader.js +24 -0
- package/esm/http/http-adapter-host.js +673 -0
- package/esm/index.js +17 -16
- package/esm/platform-adapter.host.js +132 -0
- package/esm/{adapter/endpoint-context.js → request-context.js} +4 -4
- package/esm/{adapter/request.host.js → request.host.js} +3 -0
- package/esm/response.js +1 -0
- package/i18n/en/error.json +1 -2
- package/package.json +3 -3
- package/types/augmentation/collection.augmentation.d.ts +26 -17
- package/types/augmentation/container.augmentation.d.ts +13 -0
- package/types/augmentation/resource.augmentation.d.ts +2 -2
- package/types/augmentation/singleton.augmentation.d.ts +14 -10
- package/types/augmentation/storage.augmentation.d.ts +16 -16
- package/types/{adapter/execution-context.d.ts → execution-context.d.ts} +3 -3
- package/types/{adapter/execution-context.host.d.ts → execution-context.host.d.ts} +1 -1
- package/types/{adapter/http → http/adapters}/express-adapter.d.ts +3 -3
- package/types/http/adapters/express-adapter.host.d.ts +12 -0
- package/types/{adapter/http/http-adapter.d.ts → http/adapters/node-http-adapter.d.ts} +5 -5
- package/types/http/adapters/node-http-adapter.host.d.ts +19 -0
- package/types/http/helpers/json-body-loader.d.ts +5 -0
- package/types/http/http-adapter-host.d.ts +34 -0
- package/types/{adapter/http → http}/impl/http-outgoing-message.host.d.ts +1 -1
- package/types/index.d.ts +17 -16
- package/types/{adapter/interfaces → interfaces}/request-handler.interface.d.ts +1 -1
- package/types/{adapter/platform-adapter.d.ts → platform-adapter.d.ts} +2 -2
- package/types/platform-adapter.host.d.ts +37 -0
- package/types/request-context.d.ts +10 -0
- package/types/{adapter/request.d.ts → request.d.ts} +8 -3
- package/types/{adapter/request.host.d.ts → request.host.d.ts} +7 -4
- package/types/{adapter/response.d.ts → response.d.ts} +1 -1
- package/types/{adapter/response.host.d.ts → response.host.d.ts} +2 -2
- package/cjs/adapter/http/express-adapter.host.js +0 -24
- package/cjs/adapter/http/http-adapter-base.js +0 -138
- package/cjs/adapter/http/http-adapter.js +0 -16
- package/cjs/adapter/http/request-handlers/entity-request-handler.js +0 -418
- package/cjs/adapter/http/request-handlers/parse-batch-request.js +0 -169
- package/cjs/adapter/http/request-handlers/request-handler-base.js +0 -27
- package/cjs/adapter/http/request-handlers/storage-request-handler.js +0 -133
- package/esm/adapter/http/express-adapter.host.js +0 -20
- package/esm/adapter/http/http-adapter-base.js +0 -134
- package/esm/adapter/http/http-adapter.js +0 -13
- package/esm/adapter/http/request-handlers/entity-request-handler.js +0 -413
- package/esm/adapter/http/request-handlers/parse-batch-request.js +0 -169
- package/esm/adapter/http/request-handlers/request-handler-base.js +0 -23
- package/esm/adapter/http/request-handlers/storage-request-handler.js +0 -128
- package/esm/adapter/platform-adapter.host.js +0 -103
- package/types/adapter/endpoint-context.d.ts +0 -10
- package/types/adapter/http/express-adapter.host.d.ts +0 -11
- package/types/adapter/http/http-adapter-base.d.ts +0 -23
- package/types/adapter/http/http-adapter.host.d.ts +0 -18
- package/types/adapter/http/request-handlers/entity-request-handler.d.ts +0 -24
- package/types/adapter/http/request-handlers/parse-batch-request.d.ts +0 -0
- package/types/adapter/http/request-handlers/request-handler-base.d.ts +0 -15
- package/types/adapter/http/request-handlers/storage-request-handler.d.ts +0 -23
- package/types/adapter/platform-adapter.host.d.ts +0 -33
- /package/cjs/{adapter/execution-context.js → augmentation/container.augmentation.js} +0 -0
- /package/cjs/{adapter/execution-context.host.js → execution-context.host.js} +0 -0
- /package/cjs/{adapter/interfaces/interceptor.interface.js → execution-context.js} +0 -0
- /package/cjs/{adapter/http → http}/helpers/common.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/concat-readable.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/convert-to-headers.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/convert-to-raw-headers.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/match-known-fields.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/multipart-helper.js +0 -0
- /package/cjs/{adapter/http → http}/helpers/query-parsers.js +0 -0
- /package/cjs/{adapter/http → http}/http-server-request.js +0 -0
- /package/cjs/{adapter/http → http}/http-server-response.js +0 -0
- /package/cjs/{adapter/http → http}/impl/http-incoming-message.host.js +0 -0
- /package/cjs/{adapter/http → http}/impl/http-outgoing-message.host.js +0 -0
- /package/cjs/{adapter/interfaces/logger.interface.js → interfaces/interceptor.interface.js} +0 -0
- /package/cjs/{adapter/interfaces/request-handler.interface.js → interfaces/logger.interface.js} +0 -0
- /package/cjs/{adapter/platform-adapter.js → interfaces/request-handler.interface.js} +0 -0
- /package/cjs/{adapter/request.js → platform-adapter.js} +0 -0
- /package/cjs/{adapter/response.js → request.js} +0 -0
- /package/cjs/{adapter/response.host.js → response.host.js} +0 -0
- /package/cjs/{adapter/services → services}/logger.js +0 -0
- /package/esm/{adapter/execution-context.js → augmentation/container.augmentation.js} +0 -0
- /package/esm/{adapter/execution-context.host.js → execution-context.host.js} +0 -0
- /package/esm/{adapter/interfaces/interceptor.interface.js → execution-context.js} +0 -0
- /package/esm/{adapter/http → http}/helpers/common.js +0 -0
- /package/esm/{adapter/http → http}/helpers/concat-readable.js +0 -0
- /package/esm/{adapter/http → http}/helpers/convert-to-headers.js +0 -0
- /package/esm/{adapter/http → http}/helpers/convert-to-raw-headers.js +0 -0
- /package/esm/{adapter/http → http}/helpers/match-known-fields.js +0 -0
- /package/esm/{adapter/http → http}/helpers/multipart-helper.js +0 -0
- /package/esm/{adapter/http → http}/helpers/query-parsers.js +0 -0
- /package/esm/{adapter/http → http}/http-server-request.js +0 -0
- /package/esm/{adapter/http → http}/http-server-response.js +0 -0
- /package/esm/{adapter/http → http}/impl/http-incoming-message.host.js +0 -0
- /package/esm/{adapter/http → http}/impl/http-outgoing-message.host.js +0 -0
- /package/esm/{adapter/interfaces/logger.interface.js → interfaces/interceptor.interface.js} +0 -0
- /package/esm/{adapter/interfaces/request-handler.interface.js → interfaces/logger.interface.js} +0 -0
- /package/esm/{adapter/platform-adapter.js → interfaces/request-handler.interface.js} +0 -0
- /package/esm/{adapter/request.js → platform-adapter.js} +0 -0
- /package/esm/{adapter/response.js → request.js} +0 -0
- /package/esm/{adapter/response.host.js → response.host.js} +0 -0
- /package/esm/{adapter/services → services}/logger.js +0 -0
- /package/types/{adapter/http → http}/helpers/common.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/concat-readable.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/convert-to-headers.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/convert-to-raw-headers.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/match-known-fields.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/multipart-helper.d.ts +0 -0
- /package/types/{adapter/http → http}/helpers/query-parsers.d.ts +0 -0
- /package/types/{adapter/http → http}/http-server-request.d.ts +0 -0
- /package/types/{adapter/http → http}/http-server-response.d.ts +0 -0
- /package/types/{adapter/http → http}/impl/http-incoming-message.host.d.ts +0 -0
- /package/types/{adapter/interfaces → interfaces}/interceptor.interface.d.ts +0 -0
- /package/types/{adapter/interfaces → interfaces}/logger.interface.d.ts +0 -0
- /package/types/{adapter/services → services}/logger.d.ts +0 -0
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EntityRequestHandler = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const body_parser_1 = tslib_1.__importDefault(require("body-parser"));
|
|
6
|
-
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
7
|
-
const valgen = tslib_1.__importStar(require("valgen"));
|
|
8
|
-
const common_1 = require("@opra/common");
|
|
9
|
-
const endpoint_context_js_1 = require("../../endpoint-context.js");
|
|
10
|
-
const request_host_js_1 = require("../../request.host.js");
|
|
11
|
-
const response_host_js_1 = require("../../response.host.js");
|
|
12
|
-
const query_parsers_js_1 = require("../helpers/query-parsers.js");
|
|
13
|
-
const request_handler_base_js_1 = require("./request-handler-base.js");
|
|
14
|
-
/**
|
|
15
|
-
* @class EntityRequestHandler
|
|
16
|
-
*/
|
|
17
|
-
class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase {
|
|
18
|
-
constructor(adapter) {
|
|
19
|
-
super(adapter);
|
|
20
|
-
this.adapter = adapter;
|
|
21
|
-
this.bodyLoaders = new WeakMap();
|
|
22
|
-
}
|
|
23
|
-
async processRequest(executionContext) {
|
|
24
|
-
const { incoming, outgoing } = executionContext.switchToHttp();
|
|
25
|
-
// Parse incoming message and create Request object
|
|
26
|
-
const request = await this.parseRequest(incoming);
|
|
27
|
-
if (!request)
|
|
28
|
-
return;
|
|
29
|
-
const response = new response_host_js_1.ResponseHost({ http: outgoing });
|
|
30
|
-
const context = endpoint_context_js_1.EndpointContext.from(executionContext, request, response);
|
|
31
|
-
await this.callEndpoint(context);
|
|
32
|
-
if (response.errors.length) {
|
|
33
|
-
context.errors.push(...response.errors);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
await this.sendResponse(context);
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
if (e instanceof common_1.OpraException)
|
|
41
|
-
throw e;
|
|
42
|
-
if (e instanceof valgen.ValidationError) {
|
|
43
|
-
throw new common_1.InternalServerError({
|
|
44
|
-
message: (0, common_1.translate)('error:RESPONSE_VALIDATION,', 'Response validation failed'),
|
|
45
|
-
code: 'RESPONSE_VALIDATION',
|
|
46
|
-
details: e.issues
|
|
47
|
-
}, e);
|
|
48
|
-
}
|
|
49
|
-
throw new common_1.InternalServerError(e);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
async parseRequest(incoming) {
|
|
53
|
-
const p = incoming.parsedUrl.path[0];
|
|
54
|
-
const resource = this.adapter.api.getResource(p.resource, true);
|
|
55
|
-
if (!resource)
|
|
56
|
-
throw new common_1.BadRequestError({
|
|
57
|
-
message: (0, common_1.translate)('error:SOURCE_NOT_FOUND,', 'Resource not found'),
|
|
58
|
-
code: 'SOURCE_NOT_FOUND',
|
|
59
|
-
details: {
|
|
60
|
-
path: incoming.parsedUrl.address
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
try {
|
|
64
|
-
if (resource instanceof common_1.Collection)
|
|
65
|
-
return await this.parseCollectionRequest(resource, incoming);
|
|
66
|
-
if (resource instanceof common_1.Singleton)
|
|
67
|
-
return await this.parseSingletonRequest(resource, incoming);
|
|
68
|
-
}
|
|
69
|
-
catch (e) {
|
|
70
|
-
if (e instanceof common_1.OpraException)
|
|
71
|
-
throw e;
|
|
72
|
-
if (e instanceof valgen.ValidationError) {
|
|
73
|
-
throw new common_1.BadRequestError({
|
|
74
|
-
message: (0, common_1.translate)('error:REQUEST_VALIDATION,', 'Request validation failed'),
|
|
75
|
-
code: 'REQUEST_VALIDATION',
|
|
76
|
-
details: e.issues
|
|
77
|
-
}, e);
|
|
78
|
-
}
|
|
79
|
-
throw new common_1.BadRequestError(e);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async callEndpoint(context) {
|
|
83
|
-
const request = context.request;
|
|
84
|
-
const { response } = context;
|
|
85
|
-
const resource = request.resource;
|
|
86
|
-
// Call endpoint handler method
|
|
87
|
-
let value;
|
|
88
|
-
try {
|
|
89
|
-
value = await request.controller[request.endpoint].call(request.controller, context);
|
|
90
|
-
if (value == null)
|
|
91
|
-
value = response.value;
|
|
92
|
-
const { endpoint } = request;
|
|
93
|
-
if (endpoint === 'delete' || endpoint === 'deleteMany' || endpoint === 'updateMany') {
|
|
94
|
-
let affected = 0;
|
|
95
|
-
if (typeof value === 'number')
|
|
96
|
-
affected = value;
|
|
97
|
-
if (typeof value === 'boolean')
|
|
98
|
-
affected = value ? 1 : 0;
|
|
99
|
-
if (typeof value === 'object')
|
|
100
|
-
affected = value.affected || value.affectedRows ||
|
|
101
|
-
(endpoint === 'updateMany' ? value.updated : value.deleted);
|
|
102
|
-
response.value = affected;
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
// "get" and "update" endpoints must return the entity instance, otherwise it means resource not found
|
|
106
|
-
if (value == null && (request.endpoint === 'get' || request.endpoint === 'update'))
|
|
107
|
-
throw new common_1.ResourceNotFoundError(resource.name, request.key);
|
|
108
|
-
// "findMany" endpoint should return array of entity instances
|
|
109
|
-
if (request.endpoint === 'findMany')
|
|
110
|
-
value = value == null ? [] : Array.isArray(value) ? value : [value];
|
|
111
|
-
else
|
|
112
|
-
value = value == null ? {} : Array.isArray(value) ? value[0] : value;
|
|
113
|
-
response.value = value;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
response.errors.push(error);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async sendResponse(context) {
|
|
121
|
-
const { request, response } = context;
|
|
122
|
-
const resource = request.resource;
|
|
123
|
-
const outgoing = response.switchToHttp();
|
|
124
|
-
let responseObject;
|
|
125
|
-
if (request.endpoint === 'delete' || request.endpoint === 'deleteMany') {
|
|
126
|
-
responseObject = {
|
|
127
|
-
resource: resource.name,
|
|
128
|
-
operation: 'delete',
|
|
129
|
-
affected: response.value
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
else if (request.endpoint === 'updateMany') {
|
|
133
|
-
responseObject = {
|
|
134
|
-
resource: resource.name,
|
|
135
|
-
operation: 'update',
|
|
136
|
-
affected: response.value
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
if (!response.value)
|
|
141
|
-
throw new common_1.InternalServerError(`"${request.endpoint}" endpoint should return value`);
|
|
142
|
-
const encode = resource.getEncoder(request.endpoint);
|
|
143
|
-
const data = encode(response.value, { coerce: true });
|
|
144
|
-
if (request.endpoint === 'create')
|
|
145
|
-
outgoing.statusCode = 201;
|
|
146
|
-
responseObject = {
|
|
147
|
-
resource: resource.name,
|
|
148
|
-
endpoint: request.endpoint,
|
|
149
|
-
data
|
|
150
|
-
};
|
|
151
|
-
if (request.endpoint === 'create' || request.endpoint === 'update')
|
|
152
|
-
responseObject.affected = 1;
|
|
153
|
-
if (request.endpoint === 'findMany' && response.count != null && response.count >= 0)
|
|
154
|
-
responseObject.totalCount = response.count;
|
|
155
|
-
}
|
|
156
|
-
outgoing.statusCode = outgoing.statusCode || common_1.HttpStatusCodes.OK;
|
|
157
|
-
const body = this.adapter._i18n.deep(responseObject);
|
|
158
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/opra+json; charset=utf-8');
|
|
159
|
-
outgoing.send(JSON.stringify(body));
|
|
160
|
-
outgoing.end();
|
|
161
|
-
}
|
|
162
|
-
async parseCollectionRequest(resource, incoming) {
|
|
163
|
-
if ((incoming.method === 'POST' || incoming.method === 'PATCH') && !incoming.is('json'))
|
|
164
|
-
throw new common_1.BadRequestError({ message: 'Unsupported Content-Type' });
|
|
165
|
-
const contentId = incoming.headers['content-id'];
|
|
166
|
-
const p = incoming.parsedUrl.path[0];
|
|
167
|
-
const params = incoming.parsedUrl.searchParams;
|
|
168
|
-
switch (incoming.method) {
|
|
169
|
-
case 'POST': {
|
|
170
|
-
if (p.key == null) {
|
|
171
|
-
const endpointMeta = await this.assertEndpoint(resource, 'create');
|
|
172
|
-
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
173
|
-
const decode = resource.getDecoder('create');
|
|
174
|
-
let data = await jsonReader(incoming);
|
|
175
|
-
data = decode(data, { coerce: true });
|
|
176
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
177
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
178
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
179
|
-
return new request_host_js_1.RequestHost({
|
|
180
|
-
controller: endpointMeta.controller,
|
|
181
|
-
http: incoming,
|
|
182
|
-
contentId,
|
|
183
|
-
resource,
|
|
184
|
-
endpoint: 'create',
|
|
185
|
-
data,
|
|
186
|
-
params: {
|
|
187
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
188
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
189
|
-
include: include && resource.normalizeFieldPath(include)
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
case 'DELETE': {
|
|
196
|
-
if (p.key != null) {
|
|
197
|
-
const endpointMeta = await this.assertEndpoint(resource, 'delete');
|
|
198
|
-
return new request_host_js_1.RequestHost({
|
|
199
|
-
controller: endpointMeta.controller,
|
|
200
|
-
http: incoming,
|
|
201
|
-
contentId,
|
|
202
|
-
resource,
|
|
203
|
-
endpoint: 'delete',
|
|
204
|
-
key: resource.parseKeyValue(p.key)
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
const endpointMeta = await this.assertEndpoint(resource, 'deleteMany');
|
|
208
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
209
|
-
return new request_host_js_1.RequestHost({
|
|
210
|
-
controller: endpointMeta.controller,
|
|
211
|
-
http: incoming,
|
|
212
|
-
contentId,
|
|
213
|
-
resource,
|
|
214
|
-
endpoint: 'deleteMany',
|
|
215
|
-
params: {
|
|
216
|
-
filter
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
case 'GET': {
|
|
221
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
222
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
223
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
224
|
-
if (p.key != null) {
|
|
225
|
-
const endpointMeta = await this.assertEndpoint(resource, 'get');
|
|
226
|
-
return new request_host_js_1.RequestHost({
|
|
227
|
-
controller: endpointMeta.controller,
|
|
228
|
-
http: incoming,
|
|
229
|
-
contentId,
|
|
230
|
-
resource,
|
|
231
|
-
endpoint: 'get',
|
|
232
|
-
key: resource.parseKeyValue(p.key),
|
|
233
|
-
params: {
|
|
234
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
235
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
236
|
-
include: include && resource.normalizeFieldPath(include)
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
const endpointMeta = await this.assertEndpoint(resource, 'findMany');
|
|
241
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
242
|
-
const sort = (0, query_parsers_js_1.parseArrayParam)(params.get('$sort'));
|
|
243
|
-
return new request_host_js_1.RequestHost({
|
|
244
|
-
controller: endpointMeta.controller,
|
|
245
|
-
http: incoming,
|
|
246
|
-
contentId,
|
|
247
|
-
resource,
|
|
248
|
-
endpoint: 'findMany',
|
|
249
|
-
params: {
|
|
250
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
251
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
252
|
-
include: include && resource.normalizeFieldPath(include),
|
|
253
|
-
sort: sort && resource.normalizeSortFields(sort),
|
|
254
|
-
filter,
|
|
255
|
-
limit: (0, putil_varhelpers_1.toInt)(params.get('$limit')),
|
|
256
|
-
skip: (0, putil_varhelpers_1.toInt)(params.get('$skip')),
|
|
257
|
-
distinct: (0, putil_varhelpers_1.toBoolean)(params.get('$distinct')),
|
|
258
|
-
count: (0, putil_varhelpers_1.toBoolean)(params.get('$count')),
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
case 'PATCH': {
|
|
263
|
-
if (p.key != null) {
|
|
264
|
-
const endpointMeta = await this.assertEndpoint(resource, 'update');
|
|
265
|
-
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
266
|
-
const decode = resource.getDecoder('update');
|
|
267
|
-
let data = await jsonReader(incoming);
|
|
268
|
-
data = decode(data, { coerce: true });
|
|
269
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
270
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
271
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
272
|
-
return new request_host_js_1.RequestHost({
|
|
273
|
-
controller: endpointMeta.controller,
|
|
274
|
-
http: incoming,
|
|
275
|
-
contentId,
|
|
276
|
-
resource,
|
|
277
|
-
endpoint: 'update',
|
|
278
|
-
key: resource.parseKeyValue(p.key),
|
|
279
|
-
data,
|
|
280
|
-
params: {
|
|
281
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
282
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
283
|
-
include: include && resource.normalizeFieldPath(include),
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
const endpointMeta = await this.assertEndpoint(resource, 'updateMany');
|
|
288
|
-
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
289
|
-
const decode = resource.getDecoder('updateMany');
|
|
290
|
-
let data = await jsonReader(incoming);
|
|
291
|
-
data = decode(data, { coerce: true });
|
|
292
|
-
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
293
|
-
return new request_host_js_1.RequestHost({
|
|
294
|
-
controller: endpointMeta.controller,
|
|
295
|
-
http: incoming,
|
|
296
|
-
contentId,
|
|
297
|
-
resource,
|
|
298
|
-
endpoint: 'updateMany',
|
|
299
|
-
data,
|
|
300
|
-
params: {
|
|
301
|
-
filter,
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
throw new common_1.MethodNotAllowedError({
|
|
307
|
-
message: `Collection resource do not accept http "${incoming.method}" method`
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
async parseSingletonRequest(resource, incoming) {
|
|
311
|
-
if ((incoming.method === 'POST' || incoming.method === 'PATCH') &&
|
|
312
|
-
incoming.headers['content-type'] !== 'application/json')
|
|
313
|
-
throw new common_1.BadRequestError({ message: 'Unsupported Content-Type' });
|
|
314
|
-
const contentId = incoming.headers['content-id'];
|
|
315
|
-
const params = incoming.parsedUrl.searchParams;
|
|
316
|
-
switch (incoming.method) {
|
|
317
|
-
case 'POST': {
|
|
318
|
-
const endpointMeta = await this.assertEndpoint(resource, 'create');
|
|
319
|
-
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
320
|
-
const decode = resource.getDecoder('create');
|
|
321
|
-
let data = await jsonReader(incoming);
|
|
322
|
-
data = decode(data, { coerce: true });
|
|
323
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
324
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
325
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
326
|
-
return new request_host_js_1.RequestHost({
|
|
327
|
-
controller: endpointMeta.controller,
|
|
328
|
-
http: incoming,
|
|
329
|
-
contentId,
|
|
330
|
-
resource,
|
|
331
|
-
endpoint: 'create',
|
|
332
|
-
data,
|
|
333
|
-
params: {
|
|
334
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
335
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
336
|
-
include: include && resource.normalizeFieldPath(include)
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
case 'DELETE': {
|
|
341
|
-
const endpointMeta = await this.assertEndpoint(resource, 'delete');
|
|
342
|
-
return new request_host_js_1.RequestHost({
|
|
343
|
-
controller: endpointMeta.controller,
|
|
344
|
-
http: incoming,
|
|
345
|
-
contentId,
|
|
346
|
-
resource,
|
|
347
|
-
endpoint: 'delete',
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
case 'GET': {
|
|
351
|
-
const endpointMeta = await this.assertEndpoint(resource, 'get');
|
|
352
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
353
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
354
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
355
|
-
return new request_host_js_1.RequestHost({
|
|
356
|
-
controller: endpointMeta.controller,
|
|
357
|
-
http: incoming,
|
|
358
|
-
contentId,
|
|
359
|
-
resource,
|
|
360
|
-
endpoint: 'get',
|
|
361
|
-
params: {
|
|
362
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
363
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
364
|
-
include: include && resource.normalizeFieldPath(include)
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
case 'PATCH': {
|
|
369
|
-
const endpointMeta = await this.assertEndpoint(resource, 'update');
|
|
370
|
-
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
371
|
-
const decode = resource.getDecoder('update');
|
|
372
|
-
let data = await jsonReader(incoming);
|
|
373
|
-
data = decode(data, { coerce: true });
|
|
374
|
-
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
375
|
-
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
376
|
-
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
377
|
-
return new request_host_js_1.RequestHost({
|
|
378
|
-
controller: endpointMeta.controller,
|
|
379
|
-
http: incoming,
|
|
380
|
-
contentId,
|
|
381
|
-
resource,
|
|
382
|
-
endpoint: 'update',
|
|
383
|
-
data,
|
|
384
|
-
params: {
|
|
385
|
-
pick: pick && resource.normalizeFieldPath(pick),
|
|
386
|
-
omit: omit && resource.normalizeFieldPath(omit),
|
|
387
|
-
include: include && resource.normalizeFieldPath(include),
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
throw new common_1.MethodNotAllowedError({
|
|
393
|
-
message: `Singleton resource do not accept http "${incoming.method}" method`
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
getBodyLoader(endpoint) {
|
|
397
|
-
let bodyLoader = this.bodyLoaders.get(endpoint);
|
|
398
|
-
if (!bodyLoader) {
|
|
399
|
-
const parser = body_parser_1.default.json({
|
|
400
|
-
limit: endpoint.input?.maxContentSize,
|
|
401
|
-
type: 'json'
|
|
402
|
-
});
|
|
403
|
-
bodyLoader = (incoming) => {
|
|
404
|
-
return new Promise((resolve, reject) => {
|
|
405
|
-
const next = (error) => {
|
|
406
|
-
if (error)
|
|
407
|
-
return reject(error);
|
|
408
|
-
resolve(incoming.body);
|
|
409
|
-
};
|
|
410
|
-
parser(incoming, {}, next);
|
|
411
|
-
});
|
|
412
|
-
};
|
|
413
|
-
this.bodyLoaders.set(endpoint, bodyLoader);
|
|
414
|
-
}
|
|
415
|
-
return bodyLoader;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
exports.EntityRequestHandler = EntityRequestHandler;
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// async parseMultiPart(
|
|
3
|
-
// context: TExecutionContext,
|
|
4
|
-
// url: OpraURL,
|
|
5
|
-
// headers: IncomingHttpHeaders,
|
|
6
|
-
// input: Readable,
|
|
7
|
-
// boundary: string
|
|
8
|
-
// ): Promise<BatchRequestContext> {
|
|
9
|
-
// return await new Promise((resolve, reject) => {
|
|
10
|
-
// let _resolved = false;
|
|
11
|
-
// const dicer = new Dicer({boundary});
|
|
12
|
-
// const doReject = (e) => {
|
|
13
|
-
// if (_resolved) return;
|
|
14
|
-
// _resolved = true;
|
|
15
|
-
// reject(e);
|
|
16
|
-
// taskQueue.clearQueue();
|
|
17
|
-
// dicer.destroy();
|
|
18
|
-
// }
|
|
19
|
-
// const taskQueue = new TaskQueue({concurrency: 1});
|
|
20
|
-
// taskQueue.on('error', doReject);
|
|
21
|
-
//
|
|
22
|
-
// const queries: SingleRequestContext[] = [];
|
|
23
|
-
// let partCounter = 0;
|
|
24
|
-
// dicer.on('error', doReject);
|
|
25
|
-
// dicer.on('part', part => {
|
|
26
|
-
// const partIndex = partCounter++;
|
|
27
|
-
// let header: any;
|
|
28
|
-
// const chunks: Buffer[] = [];
|
|
29
|
-
// part.on('error', doReject);
|
|
30
|
-
// part.on('header', (_header) => header = normalizeHeaders(_header));
|
|
31
|
-
// part.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
32
|
-
// part.on('end', () => {
|
|
33
|
-
// if (_resolved || !(header || chunks.length))
|
|
34
|
-
// return;
|
|
35
|
-
// const ct = header['content-type'];
|
|
36
|
-
// if (ct === 'application/http') {
|
|
37
|
-
// taskQueue.enqueue(async () => {
|
|
38
|
-
// const data = Buffer.concat(chunks);
|
|
39
|
-
// if (!(data && data.length))
|
|
40
|
-
// return;
|
|
41
|
-
// const r = HttpRequest.parse(data);
|
|
42
|
-
// await callMiddlewares(r, [jsonBodyParser]);
|
|
43
|
-
// const subUrl = new OpraURL(r.url);
|
|
44
|
-
// const contentId = header && header['content-id'];
|
|
45
|
-
// queries.push(this.parseSingleQuery({
|
|
46
|
-
// context,
|
|
47
|
-
// url: subUrl,
|
|
48
|
-
// method: r.method,
|
|
49
|
-
// headers: r.headers,
|
|
50
|
-
// body: r.body,
|
|
51
|
-
// contentId
|
|
52
|
-
// }));
|
|
53
|
-
// });
|
|
54
|
-
// } else doReject(new BadRequestError({
|
|
55
|
-
// message: 'Unaccepted "content-type" header in multipart data',
|
|
56
|
-
// details: {
|
|
57
|
-
// position: `${boundary}[${partIndex}]`
|
|
58
|
-
// }
|
|
59
|
-
// }))
|
|
60
|
-
// });
|
|
61
|
-
// });
|
|
62
|
-
// dicer.on('finish', () => {
|
|
63
|
-
// taskQueue.enqueue(() => {
|
|
64
|
-
// if (_resolved) return;
|
|
65
|
-
// _resolved = true;
|
|
66
|
-
// const batch = new BatchRequestContext({
|
|
67
|
-
// service: this.document,
|
|
68
|
-
// context,
|
|
69
|
-
// headers,
|
|
70
|
-
// queries,
|
|
71
|
-
// params: url.searchParams,
|
|
72
|
-
// continueOnError: false
|
|
73
|
-
// });
|
|
74
|
-
// resolve(batch);
|
|
75
|
-
// });
|
|
76
|
-
// });
|
|
77
|
-
// input.pipe(dicer);
|
|
78
|
-
// });
|
|
79
|
-
// }
|
|
80
|
-
// protected async sendBatchResponse(context: TExecutionContext, requestContext: BatchRequestContext) {
|
|
81
|
-
// const resp = context.getResponse();
|
|
82
|
-
// resp.setStatus(HttpStatus.OK);
|
|
83
|
-
// resp.setHeader(HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
84
|
-
// resp.setHeader(HttpHeaderCodes.Pragma, 'no-cache');
|
|
85
|
-
// resp.setHeader(HttpHeaderCodes.Expires, '-1');
|
|
86
|
-
// if (requestContext.headers) {
|
|
87
|
-
// for (const [k, v] of Object.entries(requestContext.headers)) {
|
|
88
|
-
// if (v)
|
|
89
|
-
// resp.setHeader(k, v);
|
|
90
|
-
// }
|
|
91
|
-
// }
|
|
92
|
-
// const boundary = 'batch_' + uuid();
|
|
93
|
-
// resp.setHeader(HttpHeaderCodes.Content_Type, 'multipart/mixed;boundary=' + boundary);
|
|
94
|
-
// resp.setHeader(HttpHeaderCodes.X_Opra_Version, OpraSchema.Version);
|
|
95
|
-
//
|
|
96
|
-
// const bodyBuilder = new HttpMultipartData();
|
|
97
|
-
//
|
|
98
|
-
// const chunks: any[] = [];
|
|
99
|
-
// let msgIdx = 0;
|
|
100
|
-
// for (const ctx of requestContext.queries) {
|
|
101
|
-
// msgIdx++;
|
|
102
|
-
// const out = this.createOutput(ctx);
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
// // chunks.push('--' + boundary + CRLF);
|
|
106
|
-
// // let s = 'Content-Type: application/http' + CRLF +
|
|
107
|
-
// // 'Content-Transfer-Encoding: binary' + CRLF +
|
|
108
|
-
// // 'Content-ID:' + (ctx.contentId || msgIdx) + CRLF +
|
|
109
|
-
// // CRLF +
|
|
110
|
-
// // 'HTTP/1.1 ' + out.status + (HttpStatus[out.status] || 'Unknown') + CRLF;
|
|
111
|
-
//
|
|
112
|
-
// let body = out.body;
|
|
113
|
-
// const headers = out.headers || {};
|
|
114
|
-
// if (body) {
|
|
115
|
-
// const contentType = String(headers['content-type'] || '').split(/\s*;\s*/);
|
|
116
|
-
// let charset = '';
|
|
117
|
-
// if (Highland.isStream(body)) {
|
|
118
|
-
// const l = parseInt(String(headers['content-length']), 10);
|
|
119
|
-
// if (isNaN(l))
|
|
120
|
-
// throw new TypeError('"content-length" header required for streamed responses');
|
|
121
|
-
// } else if (typeof body === 'object') {
|
|
122
|
-
// if (typeof body.stream === 'function') { // File and Blob
|
|
123
|
-
// contentType[0] = body.type || 'binary';
|
|
124
|
-
// headers['content-length'] = String(body.size);
|
|
125
|
-
// body = body.stream();
|
|
126
|
-
// } else if (Buffer.isBuffer(body)) {
|
|
127
|
-
// headers['content-length'] = String(body.length);
|
|
128
|
-
// } else {
|
|
129
|
-
// contentType[0] = contentType[0] || 'application/json';
|
|
130
|
-
// charset = 'utf-8';
|
|
131
|
-
// body = Buffer.from(JSON.stringify(body), 'utf-8');
|
|
132
|
-
// headers['content-length'] = String(body.length);
|
|
133
|
-
// }
|
|
134
|
-
// } else {
|
|
135
|
-
// contentType[0] = contentType[0] || 'text/plain';
|
|
136
|
-
// charset = 'utf-8';
|
|
137
|
-
// body = Buffer.from(String(body), 'utf-8');
|
|
138
|
-
// headers['content-length'] = String(body.length);
|
|
139
|
-
// }
|
|
140
|
-
// if (contentType[0]) {
|
|
141
|
-
// if (charset) {
|
|
142
|
-
// const i = contentType.findIndex(x => CHARSET_PATTERN.test(String(x)));
|
|
143
|
-
// if (i > 0) contentType[i] = 'charset=' + charset;
|
|
144
|
-
// else contentType.join('charset=' + charset);
|
|
145
|
-
// }
|
|
146
|
-
// headers['content-type'] = contentType.join(';');
|
|
147
|
-
// }
|
|
148
|
-
// }
|
|
149
|
-
// for (const [k, v] of Object.entries(headers))
|
|
150
|
-
// s += k + ': ' + (Array.isArray(v) ? v.join(';') : v) + CRLF
|
|
151
|
-
//
|
|
152
|
-
// chunks.push(s + CRLF);
|
|
153
|
-
//
|
|
154
|
-
// if (body) {
|
|
155
|
-
// if (typeof body === 'string')
|
|
156
|
-
// chunks.push(body + CRLF + CRLF);
|
|
157
|
-
// else {
|
|
158
|
-
// chunks.push(body);
|
|
159
|
-
// chunks.push(CRLF + CRLF);
|
|
160
|
-
// }
|
|
161
|
-
// }
|
|
162
|
-
// }
|
|
163
|
-
//
|
|
164
|
-
// chunks.push('--' + boundary + '--' + CRLF);
|
|
165
|
-
//
|
|
166
|
-
// resp.setHeader('content-type', 'multipart/mixed;boundary=' + boundary);
|
|
167
|
-
// resp.send(Highland(chunks).flatten());
|
|
168
|
-
// resp.end();
|
|
169
|
-
// }
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RequestHandlerBase = void 0;
|
|
4
|
-
const common_1 = require("@opra/common");
|
|
5
|
-
/**
|
|
6
|
-
* @class RequestHandlerBase
|
|
7
|
-
*/
|
|
8
|
-
class RequestHandlerBase {
|
|
9
|
-
constructor(adapter) {
|
|
10
|
-
this.adapter = adapter;
|
|
11
|
-
}
|
|
12
|
-
async assertEndpoint(resource, endpoint) {
|
|
13
|
-
const controller = await this.adapter.getController(resource);
|
|
14
|
-
const endpointMeta = (typeof controller?.[endpoint] === 'function') && resource.operations[endpoint];
|
|
15
|
-
if (endpointMeta)
|
|
16
|
-
return {
|
|
17
|
-
...endpointMeta,
|
|
18
|
-
controller
|
|
19
|
-
};
|
|
20
|
-
throw new common_1.ForbiddenError({
|
|
21
|
-
message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { resource: resource.name, endpoint }, `'{{resource}}' endpoint does not accept '{{endpoint}}' operations`),
|
|
22
|
-
severity: 'error',
|
|
23
|
-
code: 'RESOLVER_FORBIDDEN'
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
exports.RequestHandlerBase = RequestHandlerBase;
|