@opra/core 0.23.1 → 0.24.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/adapter/{operation-context.js → endpoint-context.js} +5 -5
- package/cjs/adapter/http/http-adapter-base.js +2 -4
- package/cjs/adapter/http/request-handlers/entity-request-handler.js +82 -68
- package/cjs/adapter/http/request-handlers/request-handler-base.js +5 -5
- package/cjs/adapter/http/request-handlers/storage-request-handler.js +16 -17
- package/cjs/adapter/platform-adapter.host.js +1 -1
- package/cjs/augmentation/resource.augmentation.js +6 -6
- package/cjs/index.js +1 -1
- package/esm/adapter/{operation-context.js → endpoint-context.js} +4 -4
- package/esm/adapter/http/http-adapter-base.js +2 -4
- package/esm/adapter/http/request-handlers/entity-request-handler.js +82 -68
- package/esm/adapter/http/request-handlers/request-handler-base.js +5 -5
- package/esm/adapter/http/request-handlers/storage-request-handler.js +16 -17
- package/esm/adapter/platform-adapter.host.js +1 -1
- package/esm/augmentation/resource.augmentation.js +7 -7
- package/esm/index.js +1 -1
- package/i18n/en/error.json +3 -2
- package/package.json +2 -2
- package/types/adapter/{operation-context.d.ts → endpoint-context.d.ts} +3 -3
- package/types/adapter/http/request-handlers/entity-request-handler.d.ts +4 -4
- package/types/adapter/http/request-handlers/request-handler-base.d.ts +1 -1
- package/types/adapter/http/request-handlers/storage-request-handler.d.ts +3 -3
- package/types/adapter/platform-adapter.d.ts +2 -2
- package/types/adapter/request.d.ts +1 -1
- package/types/adapter/response.d.ts +1 -1
- package/types/augmentation/collection.augmentation.d.ts +21 -16
- package/types/augmentation/resource.augmentation.d.ts +6 -1
- package/types/augmentation/singleton.augmentation.d.ts +14 -10
- package/types/augmentation/storage.augmentation.d.ts +9 -5
- package/types/index.d.ts +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
var
|
|
5
|
-
(function (
|
|
3
|
+
exports.EndpointContext = void 0;
|
|
4
|
+
var EndpointContext;
|
|
5
|
+
(function (EndpointContext) {
|
|
6
6
|
function from(executionContext, request, response) {
|
|
7
7
|
const out = {
|
|
8
8
|
request,
|
|
@@ -12,5 +12,5 @@ var OperationContext;
|
|
|
12
12
|
Object.setPrototypeOf(out, executionContext);
|
|
13
13
|
return out;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
})(
|
|
15
|
+
EndpointContext.from = from;
|
|
16
|
+
})(EndpointContext || (exports.EndpointContext = EndpointContext = {}));
|
|
@@ -53,9 +53,7 @@ class HttpAdapterBase extends platform_adapter_host_js_1.PlatformAdapterHost {
|
|
|
53
53
|
async processRequest(context) {
|
|
54
54
|
try {
|
|
55
55
|
const { incoming, outgoing } = context.switchToHttp();
|
|
56
|
-
if (incoming.method === 'GET' &&
|
|
57
|
-
incoming.parsedUrl.path.length &&
|
|
58
|
-
incoming.parsedUrl.path[0].resource === '$metadata') {
|
|
56
|
+
if (incoming.method === 'GET' && !incoming.parsedUrl.path.length) {
|
|
59
57
|
outgoing.setHeader('content-type', 'application/json');
|
|
60
58
|
outgoing.end(JSON.stringify(this.api.exportSchema({ webSafe: true })));
|
|
61
59
|
return;
|
|
@@ -115,7 +113,7 @@ class HttpAdapterBase extends platform_adapter_host_js_1.PlatformAdapterHost {
|
|
|
115
113
|
const body = {
|
|
116
114
|
errors: wrappedErrors.map(x => this._i18n.deep(x.toJSON()))
|
|
117
115
|
};
|
|
118
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
116
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/opra+json; charset=utf-8');
|
|
119
117
|
outgoing.setHeader(common_1.HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
120
118
|
outgoing.setHeader(common_1.HttpHeaderCodes.Pragma, 'no-cache');
|
|
121
119
|
outgoing.setHeader(common_1.HttpHeaderCodes.Expires, '-1');
|
|
@@ -6,7 +6,7 @@ const body_parser_1 = tslib_1.__importDefault(require("body-parser"));
|
|
|
6
6
|
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
7
7
|
const valgen = tslib_1.__importStar(require("valgen"));
|
|
8
8
|
const common_1 = require("@opra/common");
|
|
9
|
-
const
|
|
9
|
+
const endpoint_context_js_1 = require("../../endpoint-context.js");
|
|
10
10
|
const request_host_js_1 = require("../../request.host.js");
|
|
11
11
|
const response_host_js_1 = require("../../response.host.js");
|
|
12
12
|
const query_parsers_js_1 = require("../helpers/query-parsers.js");
|
|
@@ -27,9 +27,8 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
27
27
|
if (!request)
|
|
28
28
|
return;
|
|
29
29
|
const response = new response_host_js_1.ResponseHost({ http: outgoing });
|
|
30
|
-
const context =
|
|
31
|
-
|
|
32
|
-
await this.executeOperation(context);
|
|
30
|
+
const context = endpoint_context_js_1.EndpointContext.from(executionContext, request, response);
|
|
31
|
+
await this.callEndpoint(context);
|
|
33
32
|
if (response.errors.length) {
|
|
34
33
|
context.errors.push(...response.errors);
|
|
35
34
|
return;
|
|
@@ -52,7 +51,15 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
52
51
|
}
|
|
53
52
|
async parseRequest(incoming) {
|
|
54
53
|
const p = incoming.parsedUrl.path[0];
|
|
55
|
-
const resource = this.adapter.api.getResource(p.resource);
|
|
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
|
+
});
|
|
56
63
|
try {
|
|
57
64
|
if (resource instanceof common_1.Collection)
|
|
58
65
|
return await this.parseCollectionRequest(resource, incoming);
|
|
@@ -72,18 +79,18 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
72
79
|
throw new common_1.BadRequestError(e);
|
|
73
80
|
}
|
|
74
81
|
}
|
|
75
|
-
async
|
|
82
|
+
async callEndpoint(context) {
|
|
76
83
|
const request = context.request;
|
|
77
84
|
const { response } = context;
|
|
78
85
|
const resource = request.resource;
|
|
79
|
-
// Call
|
|
86
|
+
// Call endpoint handler method
|
|
80
87
|
let value;
|
|
81
88
|
try {
|
|
82
|
-
value = await request.controller[request.
|
|
89
|
+
value = await request.controller[request.endpoint].call(request.controller, context);
|
|
83
90
|
if (value == null)
|
|
84
91
|
value = response.value;
|
|
85
|
-
const {
|
|
86
|
-
if (
|
|
92
|
+
const { endpoint } = request;
|
|
93
|
+
if (endpoint === 'delete' || endpoint === 'deleteMany' || endpoint === 'updateMany') {
|
|
87
94
|
let affected = 0;
|
|
88
95
|
if (typeof value === 'number')
|
|
89
96
|
affected = value;
|
|
@@ -91,15 +98,15 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
91
98
|
affected = value ? 1 : 0;
|
|
92
99
|
if (typeof value === 'object')
|
|
93
100
|
affected = value.affected || value.affectedRows ||
|
|
94
|
-
(
|
|
101
|
+
(endpoint === 'updateMany' ? value.updated : value.deleted);
|
|
95
102
|
response.value = affected;
|
|
96
103
|
}
|
|
97
104
|
else {
|
|
98
|
-
// "get" and "update"
|
|
99
|
-
if (value == null && (request.
|
|
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'))
|
|
100
107
|
throw new common_1.ResourceNotFoundError(resource.name, request.key);
|
|
101
|
-
// "findMany"
|
|
102
|
-
if (request.
|
|
108
|
+
// "findMany" endpoint should return array of entity instances
|
|
109
|
+
if (request.endpoint === 'findMany')
|
|
103
110
|
value = value == null ? [] : Array.isArray(value) ? value : [value];
|
|
104
111
|
else
|
|
105
112
|
value = value == null ? {} : Array.isArray(value) ? value[0] : value;
|
|
@@ -115,33 +122,40 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
115
122
|
const resource = request.resource;
|
|
116
123
|
const outgoing = response.switchToHttp();
|
|
117
124
|
let responseObject;
|
|
118
|
-
if (request.
|
|
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') {
|
|
119
133
|
responseObject = {
|
|
120
134
|
resource: resource.name,
|
|
121
|
-
operation:
|
|
135
|
+
operation: 'update',
|
|
122
136
|
affected: response.value
|
|
123
137
|
};
|
|
124
138
|
}
|
|
125
139
|
else {
|
|
126
140
|
if (!response.value)
|
|
127
|
-
throw new common_1.InternalServerError(`"${request.
|
|
128
|
-
const encode = resource.getEncoder(request.
|
|
141
|
+
throw new common_1.InternalServerError(`"${request.endpoint}" endpoint should return value`);
|
|
142
|
+
const encode = resource.getEncoder(request.endpoint);
|
|
129
143
|
const data = encode(response.value, { coerce: true });
|
|
130
|
-
if (request.
|
|
144
|
+
if (request.endpoint === 'create')
|
|
131
145
|
outgoing.statusCode = 201;
|
|
132
146
|
responseObject = {
|
|
133
147
|
resource: resource.name,
|
|
134
|
-
|
|
148
|
+
endpoint: request.endpoint,
|
|
135
149
|
data
|
|
136
150
|
};
|
|
137
|
-
if (request.
|
|
151
|
+
if (request.endpoint === 'create' || request.endpoint === 'update')
|
|
138
152
|
responseObject.affected = 1;
|
|
139
|
-
if (request.
|
|
153
|
+
if (request.endpoint === 'findMany' && response.count != null && response.count >= 0)
|
|
140
154
|
responseObject.totalCount = response.count;
|
|
141
155
|
}
|
|
142
156
|
outgoing.statusCode = outgoing.statusCode || common_1.HttpStatusCodes.OK;
|
|
143
157
|
const body = this.adapter._i18n.deep(responseObject);
|
|
144
|
-
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
158
|
+
outgoing.setHeader(common_1.HttpHeaderCodes.Content_Type, 'application/opra+json; charset=utf-8');
|
|
145
159
|
outgoing.send(JSON.stringify(body));
|
|
146
160
|
outgoing.end();
|
|
147
161
|
}
|
|
@@ -155,8 +169,8 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
155
169
|
switch (incoming.method) {
|
|
156
170
|
case 'POST': {
|
|
157
171
|
if (p.key == null) {
|
|
158
|
-
const
|
|
159
|
-
const jsonReader = this.getBodyLoader(
|
|
172
|
+
const endpointMeta = await this.assertEndpoint(resource, 'create');
|
|
173
|
+
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
160
174
|
const decode = resource.getDecoder('create');
|
|
161
175
|
let data = await jsonReader(incoming);
|
|
162
176
|
data = decode(data, { coerce: true });
|
|
@@ -164,11 +178,11 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
164
178
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
165
179
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
166
180
|
return new request_host_js_1.RequestHost({
|
|
167
|
-
controller:
|
|
181
|
+
controller: endpointMeta.controller,
|
|
168
182
|
http: incoming,
|
|
169
183
|
contentId,
|
|
170
184
|
resource,
|
|
171
|
-
|
|
185
|
+
endpoint: 'create',
|
|
172
186
|
data,
|
|
173
187
|
params: {
|
|
174
188
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
@@ -181,24 +195,24 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
181
195
|
}
|
|
182
196
|
case 'DELETE': {
|
|
183
197
|
if (p.key != null) {
|
|
184
|
-
const
|
|
198
|
+
const endpointMeta = await this.assertEndpoint(resource, 'delete');
|
|
185
199
|
return new request_host_js_1.RequestHost({
|
|
186
|
-
controller:
|
|
200
|
+
controller: endpointMeta.controller,
|
|
187
201
|
http: incoming,
|
|
188
202
|
contentId,
|
|
189
203
|
resource,
|
|
190
|
-
|
|
204
|
+
endpoint: 'delete',
|
|
191
205
|
key: resource.parseKeyValue(p.key)
|
|
192
206
|
});
|
|
193
207
|
}
|
|
194
|
-
const
|
|
208
|
+
const endpointMeta = await this.assertEndpoint(resource, 'deleteMany');
|
|
195
209
|
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
196
210
|
return new request_host_js_1.RequestHost({
|
|
197
|
-
controller:
|
|
211
|
+
controller: endpointMeta.controller,
|
|
198
212
|
http: incoming,
|
|
199
213
|
contentId,
|
|
200
214
|
resource,
|
|
201
|
-
|
|
215
|
+
endpoint: 'deleteMany',
|
|
202
216
|
params: {
|
|
203
217
|
filter
|
|
204
218
|
}
|
|
@@ -209,13 +223,13 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
209
223
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
210
224
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
211
225
|
if (p.key != null) {
|
|
212
|
-
const
|
|
226
|
+
const endpointMeta = await this.assertEndpoint(resource, 'get');
|
|
213
227
|
return new request_host_js_1.RequestHost({
|
|
214
|
-
controller:
|
|
228
|
+
controller: endpointMeta.controller,
|
|
215
229
|
http: incoming,
|
|
216
230
|
contentId,
|
|
217
231
|
resource,
|
|
218
|
-
|
|
232
|
+
endpoint: 'get',
|
|
219
233
|
key: resource.parseKeyValue(p.key),
|
|
220
234
|
params: {
|
|
221
235
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
@@ -224,15 +238,15 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
224
238
|
}
|
|
225
239
|
});
|
|
226
240
|
}
|
|
227
|
-
const
|
|
241
|
+
const endpointMeta = await this.assertEndpoint(resource, 'findMany');
|
|
228
242
|
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
229
243
|
const sort = (0, query_parsers_js_1.parseArrayParam)(params.get('$sort'));
|
|
230
244
|
return new request_host_js_1.RequestHost({
|
|
231
|
-
controller:
|
|
245
|
+
controller: endpointMeta.controller,
|
|
232
246
|
http: incoming,
|
|
233
247
|
contentId,
|
|
234
248
|
resource,
|
|
235
|
-
|
|
249
|
+
endpoint: 'findMany',
|
|
236
250
|
params: {
|
|
237
251
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
238
252
|
omit: omit && resource.normalizeFieldPath(omit),
|
|
@@ -248,8 +262,8 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
248
262
|
}
|
|
249
263
|
case 'PATCH': {
|
|
250
264
|
if (p.key != null) {
|
|
251
|
-
const
|
|
252
|
-
const jsonReader = this.getBodyLoader(
|
|
265
|
+
const endpointMeta = await this.assertEndpoint(resource, 'update');
|
|
266
|
+
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
253
267
|
const decode = resource.getDecoder('update');
|
|
254
268
|
let data = await jsonReader(incoming);
|
|
255
269
|
data = decode(data, { coerce: true });
|
|
@@ -257,11 +271,11 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
257
271
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
258
272
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
259
273
|
return new request_host_js_1.RequestHost({
|
|
260
|
-
controller:
|
|
274
|
+
controller: endpointMeta.controller,
|
|
261
275
|
http: incoming,
|
|
262
276
|
contentId,
|
|
263
277
|
resource,
|
|
264
|
-
|
|
278
|
+
endpoint: 'update',
|
|
265
279
|
key: resource.parseKeyValue(p.key),
|
|
266
280
|
data,
|
|
267
281
|
params: {
|
|
@@ -271,18 +285,18 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
271
285
|
}
|
|
272
286
|
});
|
|
273
287
|
}
|
|
274
|
-
const
|
|
275
|
-
const jsonReader = this.getBodyLoader(
|
|
288
|
+
const endpointMeta = await this.assertEndpoint(resource, 'updateMany');
|
|
289
|
+
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
276
290
|
const decode = resource.getDecoder('updateMany');
|
|
277
291
|
let data = await jsonReader(incoming);
|
|
278
292
|
data = decode(data, { coerce: true });
|
|
279
293
|
const filter = resource.normalizeFilter(params.get('$filter'));
|
|
280
294
|
return new request_host_js_1.RequestHost({
|
|
281
|
-
controller:
|
|
295
|
+
controller: endpointMeta.controller,
|
|
282
296
|
http: incoming,
|
|
283
297
|
contentId,
|
|
284
298
|
resource,
|
|
285
|
-
|
|
299
|
+
endpoint: 'updateMany',
|
|
286
300
|
data,
|
|
287
301
|
params: {
|
|
288
302
|
filter,
|
|
@@ -291,7 +305,7 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
291
305
|
}
|
|
292
306
|
}
|
|
293
307
|
throw new common_1.MethodNotAllowedError({
|
|
294
|
-
message: `Collection
|
|
308
|
+
message: `Collection resource do not accept http "${incoming.method}" method`
|
|
295
309
|
});
|
|
296
310
|
}
|
|
297
311
|
async parseSingletonRequest(resource, incoming) {
|
|
@@ -302,8 +316,8 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
302
316
|
const params = incoming.parsedUrl.searchParams;
|
|
303
317
|
switch (incoming.method) {
|
|
304
318
|
case 'POST': {
|
|
305
|
-
const
|
|
306
|
-
const jsonReader = this.getBodyLoader(
|
|
319
|
+
const endpointMeta = await this.assertEndpoint(resource, 'create');
|
|
320
|
+
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
307
321
|
const decode = resource.getDecoder('create');
|
|
308
322
|
let data = await jsonReader(incoming);
|
|
309
323
|
data = decode(data, { coerce: true });
|
|
@@ -311,11 +325,11 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
311
325
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
312
326
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
313
327
|
return new request_host_js_1.RequestHost({
|
|
314
|
-
controller:
|
|
328
|
+
controller: endpointMeta.controller,
|
|
315
329
|
http: incoming,
|
|
316
330
|
contentId,
|
|
317
331
|
resource,
|
|
318
|
-
|
|
332
|
+
endpoint: 'create',
|
|
319
333
|
data,
|
|
320
334
|
params: {
|
|
321
335
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
@@ -325,26 +339,26 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
325
339
|
});
|
|
326
340
|
}
|
|
327
341
|
case 'DELETE': {
|
|
328
|
-
const
|
|
342
|
+
const endpointMeta = await this.assertEndpoint(resource, 'delete');
|
|
329
343
|
return new request_host_js_1.RequestHost({
|
|
330
|
-
controller:
|
|
344
|
+
controller: endpointMeta.controller,
|
|
331
345
|
http: incoming,
|
|
332
346
|
contentId,
|
|
333
347
|
resource,
|
|
334
|
-
|
|
348
|
+
endpoint: 'delete',
|
|
335
349
|
});
|
|
336
350
|
}
|
|
337
351
|
case 'GET': {
|
|
338
|
-
const
|
|
352
|
+
const endpointMeta = await this.assertEndpoint(resource, 'get');
|
|
339
353
|
const pick = (0, query_parsers_js_1.parseArrayParam)(params.get('$pick'));
|
|
340
354
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
341
355
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
342
356
|
return new request_host_js_1.RequestHost({
|
|
343
|
-
controller:
|
|
357
|
+
controller: endpointMeta.controller,
|
|
344
358
|
http: incoming,
|
|
345
359
|
contentId,
|
|
346
360
|
resource,
|
|
347
|
-
|
|
361
|
+
endpoint: 'get',
|
|
348
362
|
params: {
|
|
349
363
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
350
364
|
omit: omit && resource.normalizeFieldPath(omit),
|
|
@@ -353,8 +367,8 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
353
367
|
});
|
|
354
368
|
}
|
|
355
369
|
case 'PATCH': {
|
|
356
|
-
const
|
|
357
|
-
const jsonReader = this.getBodyLoader(
|
|
370
|
+
const endpointMeta = await this.assertEndpoint(resource, 'update');
|
|
371
|
+
const jsonReader = this.getBodyLoader(endpointMeta);
|
|
358
372
|
const decode = resource.getDecoder('update');
|
|
359
373
|
let data = await jsonReader(incoming);
|
|
360
374
|
data = decode(data, { coerce: true });
|
|
@@ -362,11 +376,11 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
362
376
|
const omit = (0, query_parsers_js_1.parseArrayParam)(params.get('$omit'));
|
|
363
377
|
const include = (0, query_parsers_js_1.parseArrayParam)(params.get('$include'));
|
|
364
378
|
return new request_host_js_1.RequestHost({
|
|
365
|
-
controller:
|
|
379
|
+
controller: endpointMeta.controller,
|
|
366
380
|
http: incoming,
|
|
367
381
|
contentId,
|
|
368
382
|
resource,
|
|
369
|
-
|
|
383
|
+
endpoint: 'update',
|
|
370
384
|
data,
|
|
371
385
|
params: {
|
|
372
386
|
pick: pick && resource.normalizeFieldPath(pick),
|
|
@@ -377,14 +391,14 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
377
391
|
}
|
|
378
392
|
}
|
|
379
393
|
throw new common_1.MethodNotAllowedError({
|
|
380
|
-
message: `Singleton
|
|
394
|
+
message: `Singleton resource do not accept http "${incoming.method}" method`
|
|
381
395
|
});
|
|
382
396
|
}
|
|
383
|
-
getBodyLoader(
|
|
384
|
-
let bodyLoader = this.bodyLoaders.get(
|
|
397
|
+
getBodyLoader(endpoint) {
|
|
398
|
+
let bodyLoader = this.bodyLoaders.get(endpoint);
|
|
385
399
|
if (!bodyLoader) {
|
|
386
400
|
const parser = body_parser_1.default.json({
|
|
387
|
-
limit:
|
|
401
|
+
limit: endpoint.input?.maxContentSize,
|
|
388
402
|
type: 'json'
|
|
389
403
|
});
|
|
390
404
|
bodyLoader = (incoming) => {
|
|
@@ -397,7 +411,7 @@ class EntityRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
397
411
|
parser(incoming, {}, next);
|
|
398
412
|
});
|
|
399
413
|
};
|
|
400
|
-
this.bodyLoaders.set(
|
|
414
|
+
this.bodyLoaders.set(endpoint, bodyLoader);
|
|
401
415
|
}
|
|
402
416
|
return bodyLoader;
|
|
403
417
|
}
|
|
@@ -9,16 +9,16 @@ class RequestHandlerBase {
|
|
|
9
9
|
constructor(adapter) {
|
|
10
10
|
this.adapter = adapter;
|
|
11
11
|
}
|
|
12
|
-
async
|
|
12
|
+
async assertEndpoint(resource, endpoint) {
|
|
13
13
|
const controller = await this.adapter.getController(resource);
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
14
|
+
const endpointMeta = (typeof controller?.[endpoint] === 'function') && resource.operations[endpoint];
|
|
15
|
+
if (endpointMeta)
|
|
16
16
|
return {
|
|
17
|
-
...
|
|
17
|
+
...endpointMeta,
|
|
18
18
|
controller
|
|
19
19
|
};
|
|
20
20
|
throw new common_1.ForbiddenError({
|
|
21
|
-
message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { resource: resource.name,
|
|
21
|
+
message: (0, common_1.translate)('RESOLVER_FORBIDDEN', { resource: resource.name, endpoint }, `'{{resource}}' endpoint does not accept '{{endpoint}}' operations`),
|
|
22
22
|
severity: 'error',
|
|
23
23
|
code: 'RESOLVER_FORBIDDEN'
|
|
24
24
|
});
|
|
@@ -5,7 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
|
|
6
6
|
const os_1 = tslib_1.__importDefault(require("os"));
|
|
7
7
|
const common_1 = require("@opra/common");
|
|
8
|
-
const
|
|
8
|
+
const endpoint_context_js_1 = require("../../endpoint-context.js");
|
|
9
9
|
const request_host_js_1 = require("../../request.host.js");
|
|
10
10
|
const response_host_js_1 = require("../../response.host.js");
|
|
11
11
|
const multipart_helper_js_1 = require("../helpers/multipart-helper.js");
|
|
@@ -26,9 +26,8 @@ class StorageRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
26
26
|
if (!request)
|
|
27
27
|
return;
|
|
28
28
|
const response = new response_host_js_1.ResponseHost({ http: outgoing });
|
|
29
|
-
const context =
|
|
30
|
-
|
|
31
|
-
await this.executeOperation(context);
|
|
29
|
+
const context = endpoint_context_js_1.EndpointContext.from(executionContext, request, response);
|
|
30
|
+
await this.callEndpoint(context);
|
|
32
31
|
if (response.errors.length) {
|
|
33
32
|
context.errors.push(...response.errors);
|
|
34
33
|
return;
|
|
@@ -44,30 +43,30 @@ class StorageRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
44
43
|
return;
|
|
45
44
|
switch (incoming.method) {
|
|
46
45
|
case 'GET': {
|
|
47
|
-
const
|
|
46
|
+
const endpointMeta = await this.assertEndpoint(resource, 'get');
|
|
48
47
|
return new request_host_js_1.RequestHost({
|
|
49
|
-
controller:
|
|
48
|
+
controller: endpointMeta.controller,
|
|
50
49
|
http: incoming,
|
|
51
50
|
resource,
|
|
52
|
-
|
|
51
|
+
endpoint: 'get',
|
|
53
52
|
contentId
|
|
54
53
|
});
|
|
55
54
|
}
|
|
56
55
|
case 'DELETE': {
|
|
57
|
-
const
|
|
56
|
+
const endpointMeta = await this.assertEndpoint(resource, 'delete');
|
|
58
57
|
return new request_host_js_1.RequestHost({
|
|
59
|
-
controller:
|
|
58
|
+
controller: endpointMeta.controller,
|
|
60
59
|
http: incoming,
|
|
61
60
|
resource,
|
|
62
|
-
|
|
61
|
+
endpoint: 'delete',
|
|
63
62
|
contentId
|
|
64
63
|
});
|
|
65
64
|
}
|
|
66
65
|
case 'POST': {
|
|
67
|
-
const
|
|
66
|
+
const endpointMeta = await this.assertEndpoint(resource, 'post');
|
|
68
67
|
await promises_1.default.mkdir(this._uploadDir, { recursive: true });
|
|
69
68
|
const multipartIterator = new multipart_helper_js_1.MultipartIterator(incoming, {
|
|
70
|
-
...
|
|
69
|
+
...endpointMeta,
|
|
71
70
|
filename: () => this.adapter.serviceName + '_p' + process.pid +
|
|
72
71
|
't' + String(Date.now()).substring(8) + 'r' + (0, common_1.uid)(12)
|
|
73
72
|
});
|
|
@@ -78,10 +77,10 @@ class StorageRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
78
77
|
await multipartIterator.deleteFiles().catch(() => void 0);
|
|
79
78
|
});
|
|
80
79
|
return new request_host_js_1.RequestHost({
|
|
81
|
-
controller:
|
|
80
|
+
controller: endpointMeta.controller,
|
|
82
81
|
http: incoming,
|
|
83
82
|
resource,
|
|
84
|
-
|
|
83
|
+
endpoint: 'post',
|
|
85
84
|
contentId,
|
|
86
85
|
parts: multipartIterator
|
|
87
86
|
});
|
|
@@ -94,13 +93,13 @@ class StorageRequestHandler extends request_handler_base_js_1.RequestHandlerBase
|
|
|
94
93
|
throw new common_1.BadRequestError(e);
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
|
-
async
|
|
96
|
+
async callEndpoint(context) {
|
|
98
97
|
const request = context.request;
|
|
99
98
|
const { response } = context;
|
|
100
|
-
// Call
|
|
99
|
+
// Call endpoint handler method
|
|
101
100
|
let value;
|
|
102
101
|
try {
|
|
103
|
-
value = await request.controller[request.
|
|
102
|
+
value = await request.controller[request.endpoint].call(request.controller, context);
|
|
104
103
|
if (response.value == null)
|
|
105
104
|
response.value = value;
|
|
106
105
|
}
|
|
@@ -67,7 +67,7 @@ class PlatformAdapterHost extends strict_typed_events_1.AsyncEventEmitter {
|
|
|
67
67
|
this._i18n = this._i18n || common_1.I18n.defaultInstance;
|
|
68
68
|
if (!this._i18n.isInitialized)
|
|
69
69
|
await this._i18n.init();
|
|
70
|
-
// Initialize all
|
|
70
|
+
// Initialize all resources
|
|
71
71
|
for (const resource of this.api.resources.values()) {
|
|
72
72
|
await this.getController(resource);
|
|
73
73
|
}
|
|
@@ -12,15 +12,15 @@ common_1.Resource.prototype._construct = function (init) {
|
|
|
12
12
|
};
|
|
13
13
|
common_1.Collection.OnInit = common_1.Singleton.OnInit = function () {
|
|
14
14
|
return (target, propertyKey) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
Reflect.defineMetadata(common_1.
|
|
15
|
+
const sourceMetadata = (Reflect.getOwnMetadata(common_1.SOURCE_METADATA, target.constructor) || {});
|
|
16
|
+
sourceMetadata.onInit = target[propertyKey];
|
|
17
|
+
Reflect.defineMetadata(common_1.SOURCE_METADATA, target.constructor, sourceMetadata);
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
20
|
common_1.Collection.OnShutdown = common_1.Singleton.OnShutdown = function () {
|
|
21
21
|
return (target, propertyKey) => {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
Reflect.defineMetadata(common_1.
|
|
22
|
+
const sourceMetadata = (Reflect.getOwnMetadata(common_1.SOURCE_METADATA, target.constructor) || {});
|
|
23
|
+
sourceMetadata.onShutdown = target[propertyKey];
|
|
24
|
+
Reflect.defineMetadata(common_1.SOURCE_METADATA, target.constructor, sourceMetadata);
|
|
25
25
|
};
|
|
26
26
|
};
|
package/cjs/index.js
CHANGED
|
@@ -8,7 +8,7 @@ require("./augmentation/singleton.augmentation.js");
|
|
|
8
8
|
require("./augmentation/storage.augmentation.js");
|
|
9
9
|
tslib_1.__exportStar(require("./types.js"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./adapter/execution-context.js"), exports);
|
|
11
|
-
tslib_1.__exportStar(require("./adapter/
|
|
11
|
+
tslib_1.__exportStar(require("./adapter/endpoint-context.js"), exports);
|
|
12
12
|
tslib_1.__exportStar(require("./adapter/platform-adapter.js"), exports);
|
|
13
13
|
tslib_1.__exportStar(require("./adapter/request.js"), exports);
|
|
14
14
|
tslib_1.__exportStar(require("./adapter/response.js"), exports);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export var
|
|
2
|
-
(function (
|
|
1
|
+
export var EndpointContext;
|
|
2
|
+
(function (EndpointContext) {
|
|
3
3
|
function from(executionContext, request, response) {
|
|
4
4
|
const out = {
|
|
5
5
|
request,
|
|
@@ -9,5 +9,5 @@ export var OperationContext;
|
|
|
9
9
|
Object.setPrototypeOf(out, executionContext);
|
|
10
10
|
return out;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
})(
|
|
12
|
+
EndpointContext.from = from;
|
|
13
|
+
})(EndpointContext || (EndpointContext = {}));
|
|
@@ -50,9 +50,7 @@ export class HttpAdapterBase extends PlatformAdapterHost {
|
|
|
50
50
|
async processRequest(context) {
|
|
51
51
|
try {
|
|
52
52
|
const { incoming, outgoing } = context.switchToHttp();
|
|
53
|
-
if (incoming.method === 'GET' &&
|
|
54
|
-
incoming.parsedUrl.path.length &&
|
|
55
|
-
incoming.parsedUrl.path[0].resource === '$metadata') {
|
|
53
|
+
if (incoming.method === 'GET' && !incoming.parsedUrl.path.length) {
|
|
56
54
|
outgoing.setHeader('content-type', 'application/json');
|
|
57
55
|
outgoing.end(JSON.stringify(this.api.exportSchema({ webSafe: true })));
|
|
58
56
|
return;
|
|
@@ -112,7 +110,7 @@ export class HttpAdapterBase extends PlatformAdapterHost {
|
|
|
112
110
|
const body = {
|
|
113
111
|
errors: wrappedErrors.map(x => this._i18n.deep(x.toJSON()))
|
|
114
112
|
};
|
|
115
|
-
outgoing.setHeader(HttpHeaderCodes.Content_Type, 'application/json; charset=utf-8');
|
|
113
|
+
outgoing.setHeader(HttpHeaderCodes.Content_Type, 'application/opra+json; charset=utf-8');
|
|
116
114
|
outgoing.setHeader(HttpHeaderCodes.Cache_Control, 'no-cache');
|
|
117
115
|
outgoing.setHeader(HttpHeaderCodes.Pragma, 'no-cache');
|
|
118
116
|
outgoing.setHeader(HttpHeaderCodes.Expires, '-1');
|