@opra/core 0.0.8 → 0.0.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/cjs/exception/api-exception.js +30 -33
- package/cjs/exception/errors/bad-request.error.js +6 -3
- package/cjs/exception/errors/failed-dependency.error.js +6 -3
- package/cjs/exception/errors/forbidden.error.js +6 -3
- package/cjs/exception/errors/internal-server.error.js +9 -4
- package/cjs/exception/errors/method-not-allowed.error.js +6 -3
- package/cjs/exception/errors/not-found.error.js +6 -3
- package/cjs/exception/errors/unauthorized.error.js +6 -3
- package/cjs/exception/errors/unprocessable-entity.error.js +6 -3
- package/cjs/exception/wrap-error.js +1 -1
- package/cjs/implementation/adapter/adapter.js +29 -26
- package/cjs/implementation/adapter/express-adapter.js +40 -9
- package/cjs/implementation/adapter/http-adapter.js +27 -34
- package/cjs/implementation/{execution-context.js → query-context.js} +18 -22
- package/cjs/implementation/resource/entity-resource-handler.js +16 -12
- package/cjs/implementation/resource/resource-handler.js +1 -1
- package/cjs/implementation/schema-generator.js +38 -51
- package/cjs/index.js +3 -4
- package/cjs/interfaces/{http-context.interface.js → execution-context.interface.js} +0 -0
- package/cjs/interfaces/{execution-query.interface.js → query.interface.js} +16 -16
- package/cjs/utils/internal-data-types.js +54 -17
- package/esm/exception/api-exception.d.ts +3 -2
- package/esm/exception/api-exception.js +30 -33
- package/esm/exception/errors/bad-request.error.d.ts +2 -1
- package/esm/exception/errors/bad-request.error.js +6 -3
- package/esm/exception/errors/failed-dependency.error.d.ts +2 -1
- package/esm/exception/errors/failed-dependency.error.js +6 -3
- package/esm/exception/errors/forbidden.error.d.ts +2 -1
- package/esm/exception/errors/forbidden.error.js +6 -3
- package/esm/exception/errors/internal-server.error.d.ts +2 -1
- package/esm/exception/errors/internal-server.error.js +8 -4
- package/esm/exception/errors/method-not-allowed.error.d.ts +2 -1
- package/esm/exception/errors/method-not-allowed.error.js +6 -3
- package/esm/exception/errors/not-found.error.d.ts +2 -1
- package/esm/exception/errors/not-found.error.js +6 -3
- package/esm/exception/errors/unauthorized.error.d.ts +2 -1
- package/esm/exception/errors/unauthorized.error.js +6 -3
- package/esm/exception/errors/unprocessable-entity.error.d.ts +2 -1
- package/esm/exception/errors/unprocessable-entity.error.js +6 -3
- package/esm/exception/wrap-error.js +1 -1
- package/esm/implementation/adapter/adapter.d.ts +22 -14
- package/esm/implementation/adapter/adapter.js +29 -26
- package/esm/implementation/adapter/express-adapter.d.ts +2 -2
- package/esm/implementation/adapter/express-adapter.js +40 -9
- package/esm/implementation/adapter/http-adapter.d.ts +11 -12
- package/esm/implementation/adapter/http-adapter.js +27 -34
- package/esm/implementation/query-context.d.ts +32 -0
- package/esm/implementation/{execution-context.js → query-context.js} +15 -18
- package/esm/implementation/resource/container-resource-handler.d.ts +2 -2
- package/esm/implementation/resource/entity-resource-handler.d.ts +3 -3
- package/esm/implementation/resource/entity-resource-handler.js +16 -12
- package/esm/implementation/resource/resource-handler.d.ts +3 -3
- package/esm/implementation/resource/resource-handler.js +1 -1
- package/esm/implementation/schema-generator.js +38 -51
- package/esm/index.d.ts +3 -4
- package/esm/index.js +3 -4
- package/esm/interfaces/execution-context.interface.d.ts +39 -0
- package/esm/interfaces/{http-context.interface.js → execution-context.interface.js} +0 -0
- package/esm/interfaces/{execution-query.interface.d.ts → query.interface.d.ts} +31 -25
- package/esm/interfaces/{execution-query.interface.js → query.interface.js} +15 -15
- package/esm/services/entity-resource-controller.d.ts +11 -11
- package/esm/utils/internal-data-types.d.ts +2 -1
- package/esm/utils/internal-data-types.js +53 -16
- package/package.json +6 -5
- package/cjs/interfaces/user-context.interface.js +0 -2
- package/esm/implementation/execution-context.d.ts +0 -42
- package/esm/interfaces/http-context.interface.d.ts +0 -23
- package/esm/interfaces/user-context.interface.d.ts +0 -3
- package/esm/interfaces/user-context.interface.js +0 -1
|
@@ -13,52 +13,49 @@ class ApiException extends Error {
|
|
|
13
13
|
constructor(response, cause) {
|
|
14
14
|
super('');
|
|
15
15
|
this._initName();
|
|
16
|
+
this.status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
17
|
+
cause = cause || (response instanceof Error ? response : undefined);
|
|
16
18
|
if (cause)
|
|
17
19
|
Object.defineProperty(this, 'cause', { enumerable: false, configurable: true, writable: true, value: cause });
|
|
18
|
-
else if (response instanceof Error)
|
|
19
|
-
Object.defineProperty(this, 'cause', { enumerable: false, configurable: true, writable: true, value: response });
|
|
20
|
-
this.status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
21
|
-
this._initResponse(response);
|
|
22
|
-
}
|
|
23
|
-
setStatus(status) {
|
|
24
|
-
this.status = status;
|
|
25
|
-
return this;
|
|
26
|
-
}
|
|
27
|
-
_initName() {
|
|
28
|
-
this.name = this.constructor.name;
|
|
29
|
-
}
|
|
30
|
-
_initResponse(init) {
|
|
31
|
-
if (init && typeof init === 'object') {
|
|
32
|
-
const x = init;
|
|
33
|
-
if (typeof x.status === 'number')
|
|
34
|
-
this.setStatus(x.status);
|
|
35
|
-
else if (typeof x.getStatus === 'function')
|
|
36
|
-
this.setStatus(x.getStatus());
|
|
37
|
-
}
|
|
38
|
-
if (typeof init === 'object') {
|
|
39
|
-
const x = init;
|
|
40
|
-
this.response = {
|
|
41
|
-
message: x.message || x.details || ('' + init),
|
|
42
|
-
};
|
|
43
|
-
if (!(init instanceof Error))
|
|
44
|
-
Object.assign(this.response, init);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this.response = {
|
|
48
|
-
message: '' + init,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
20
|
if (this.cause instanceof Error && this.cause.stack) {
|
|
52
21
|
if (ApiException.stackAsDiagnostics)
|
|
53
22
|
this.response.diagnostics = this.cause.stack.split('\n');
|
|
54
23
|
this.stack = this.cause.stack;
|
|
55
24
|
}
|
|
25
|
+
if (response instanceof Error)
|
|
26
|
+
this._initErrorInstance(response);
|
|
27
|
+
else if (typeof response === 'string')
|
|
28
|
+
this._initResponse({ message: response });
|
|
29
|
+
else
|
|
30
|
+
this._initResponse(response);
|
|
56
31
|
if (!this.response.severity)
|
|
57
32
|
if (this.status >= 500)
|
|
58
33
|
this.response.severity = 'fatal';
|
|
59
34
|
else
|
|
60
35
|
this.response.severity = 'error';
|
|
61
36
|
}
|
|
37
|
+
setStatus(status) {
|
|
38
|
+
this.status = status;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
_initName() {
|
|
42
|
+
this.name = this.constructor.name;
|
|
43
|
+
}
|
|
44
|
+
_initErrorInstance(init) {
|
|
45
|
+
this._initResponse({
|
|
46
|
+
message: init.message
|
|
47
|
+
});
|
|
48
|
+
if (typeof init.status === 'number')
|
|
49
|
+
this.setStatus(init.status);
|
|
50
|
+
else if (typeof init.getStatus === 'function')
|
|
51
|
+
this.setStatus(init.getStatus());
|
|
52
|
+
}
|
|
53
|
+
_initResponse(response) {
|
|
54
|
+
this.response = {
|
|
55
|
+
message: 'Unknown error',
|
|
56
|
+
...response
|
|
57
|
+
};
|
|
58
|
+
}
|
|
62
59
|
static wrap(response) {
|
|
63
60
|
if (response instanceof ApiException)
|
|
64
61
|
return response;
|
|
@@ -11,13 +11,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
11
11
|
*/
|
|
12
12
|
class BadRequestError extends api_exception_js_1.ApiException {
|
|
13
13
|
constructor(response, cause) {
|
|
14
|
-
super(
|
|
14
|
+
super(response, cause);
|
|
15
|
+
this.status = index_js_1.HttpStatus.BAD_REQUEST;
|
|
16
|
+
}
|
|
17
|
+
_initResponse(response) {
|
|
18
|
+
super._initResponse({
|
|
15
19
|
message: (0, i18n_1.translate)('error:BAD_REQUEST', 'Bad request'),
|
|
16
20
|
severity: 'error',
|
|
17
21
|
code: 'BAD_REQUEST',
|
|
18
22
|
...response
|
|
19
|
-
}
|
|
20
|
-
this.status = index_js_1.HttpStatus.BAD_REQUEST;
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
exports.BadRequestError = BadRequestError;
|
|
@@ -10,13 +10,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
10
10
|
*/
|
|
11
11
|
class FailedDependencyError extends api_exception_js_1.ApiException {
|
|
12
12
|
constructor(response, cause) {
|
|
13
|
-
super(
|
|
13
|
+
super(response, cause);
|
|
14
|
+
this.status = index_js_1.HttpStatus.FAILED_DEPENDENCY;
|
|
15
|
+
}
|
|
16
|
+
_initResponse(response) {
|
|
17
|
+
super._initResponse({
|
|
14
18
|
message: (0, i18n_1.translate)('error:FAILED_DEPENDENCY', 'The request failed due to failure of a previous request.'),
|
|
15
19
|
severity: 'error',
|
|
16
20
|
code: 'FAILED_DEPENDENCY',
|
|
17
21
|
...response
|
|
18
|
-
}
|
|
19
|
-
this.status = index_js_1.HttpStatus.FAILED_DEPENDENCY;
|
|
22
|
+
});
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
exports.FailedDependencyError = FailedDependencyError;
|
|
@@ -12,13 +12,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
12
12
|
*/
|
|
13
13
|
class ForbiddenError extends api_exception_js_1.ApiException {
|
|
14
14
|
constructor(response, cause) {
|
|
15
|
-
super(
|
|
15
|
+
super(response, cause);
|
|
16
|
+
this.status = index_js_1.HttpStatus.FORBIDDEN;
|
|
17
|
+
}
|
|
18
|
+
_initResponse(response) {
|
|
19
|
+
super._initResponse({
|
|
16
20
|
message: (0, i18n_1.translate)('error:FORBIDDEN', 'Forbidden'),
|
|
17
21
|
severity: 'error',
|
|
18
22
|
code: 'FORBIDDEN',
|
|
19
23
|
...response
|
|
20
|
-
}
|
|
21
|
-
this.status = index_js_1.HttpStatus.FORBIDDEN;
|
|
24
|
+
});
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
exports.ForbiddenError = ForbiddenError;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InternalServerError = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
4
6
|
const i18n_1 = require("@opra/i18n");
|
|
5
7
|
const index_js_1 = require("../../enums/index.js");
|
|
6
8
|
const api_exception_js_1 = require("../api-exception.js");
|
|
@@ -10,13 +12,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
10
12
|
*/
|
|
11
13
|
class InternalServerError extends api_exception_js_1.ApiException {
|
|
12
14
|
constructor(response, cause) {
|
|
13
|
-
super(
|
|
15
|
+
super(response, cause);
|
|
16
|
+
this.status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
17
|
+
}
|
|
18
|
+
_initResponse(response) {
|
|
19
|
+
super._initResponse({
|
|
14
20
|
message: (0, i18n_1.translate)('error:INTERNAL_SERVER_ERROR', 'Internal server error'),
|
|
15
21
|
severity: 'error',
|
|
16
22
|
code: 'INTERNAL_SERVER_ERROR',
|
|
17
|
-
...response
|
|
18
|
-
}
|
|
19
|
-
this.status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
23
|
+
...lodash_1.default.omitBy(response, lodash_1.default.isNil)
|
|
24
|
+
});
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
exports.InternalServerError = InternalServerError;
|
|
@@ -11,13 +11,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
11
11
|
*/
|
|
12
12
|
class MethodNotAllowedError extends api_exception_js_1.ApiException {
|
|
13
13
|
constructor(response, cause) {
|
|
14
|
-
super(
|
|
14
|
+
super(response, cause);
|
|
15
|
+
this.status = index_js_1.HttpStatus.METHOD_NOT_ALLOWED;
|
|
16
|
+
}
|
|
17
|
+
_initResponse(response) {
|
|
18
|
+
super._initResponse({
|
|
15
19
|
message: (0, i18n_1.translate)('error:METHOD_NOT_ALLOWED', 'Method Not Allowed'),
|
|
16
20
|
severity: 'error',
|
|
17
21
|
code: 'METHOD_NOT_ALLOWED',
|
|
18
22
|
...response
|
|
19
|
-
}
|
|
20
|
-
this.status = index_js_1.HttpStatus.METHOD_NOT_ALLOWED;
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
exports.MethodNotAllowedError = MethodNotAllowedError;
|
|
@@ -14,13 +14,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
14
14
|
*/
|
|
15
15
|
class NotFoundError extends api_exception_js_1.ApiException {
|
|
16
16
|
constructor(response, cause) {
|
|
17
|
-
super(
|
|
17
|
+
super(response, cause);
|
|
18
|
+
this.status = index_js_1.HttpStatus.NOT_FOUND;
|
|
19
|
+
}
|
|
20
|
+
_initResponse(response) {
|
|
21
|
+
super._initResponse({
|
|
18
22
|
message: (0, i18n_1.translate)('error:NOT_FOUND', 'Not found'),
|
|
19
23
|
severity: 'error',
|
|
20
24
|
code: 'NOT_FOUND',
|
|
21
25
|
...response
|
|
22
|
-
}
|
|
23
|
-
this.status = index_js_1.HttpStatus.NOT_FOUND;
|
|
26
|
+
});
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
exports.NotFoundError = NotFoundError;
|
|
@@ -11,13 +11,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
11
11
|
*/
|
|
12
12
|
class UnauthorizedError extends api_exception_js_1.ApiException {
|
|
13
13
|
constructor(response, cause) {
|
|
14
|
-
super(
|
|
14
|
+
super(response, cause);
|
|
15
|
+
this.status = index_js_1.HttpStatus.UNAUTHORIZED;
|
|
16
|
+
}
|
|
17
|
+
_initResponse(response) {
|
|
18
|
+
super._initResponse({
|
|
15
19
|
message: (0, i18n_1.translate)('error:UNAUTHORIZED', 'Unauthorized'),
|
|
16
20
|
severity: 'error',
|
|
17
21
|
code: 'UNAUTHORIZED',
|
|
18
22
|
...response
|
|
19
|
-
}
|
|
20
|
-
this.status = index_js_1.HttpStatus.UNAUTHORIZED;
|
|
23
|
+
});
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
exports.UnauthorizedError = UnauthorizedError;
|
|
@@ -10,13 +10,16 @@ const api_exception_js_1 = require("../api-exception.js");
|
|
|
10
10
|
*/
|
|
11
11
|
class UnprocessableEntityError extends api_exception_js_1.ApiException {
|
|
12
12
|
constructor(response, cause) {
|
|
13
|
-
super(
|
|
13
|
+
super(response, cause);
|
|
14
|
+
this.status = index_js_1.HttpStatus.UNPROCESSABLE_ENTITY;
|
|
15
|
+
}
|
|
16
|
+
_initResponse(response) {
|
|
17
|
+
super._initResponse({
|
|
14
18
|
message: (0, i18n_1.translate)('error:UNPROCESSABLE_ENTITY', 'Unprocessable entity'),
|
|
15
19
|
severity: 'error',
|
|
16
20
|
code: 'UNPROCESSABLE_ENTITY',
|
|
17
21
|
...response
|
|
18
|
-
}
|
|
19
|
-
this.status = index_js_1.HttpStatus.UNPROCESSABLE_ENTITY;
|
|
22
|
+
});
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
exports.UnprocessableEntityError = UnprocessableEntityError;
|
|
@@ -10,7 +10,7 @@ function wrapError(response) {
|
|
|
10
10
|
const x = response;
|
|
11
11
|
if (typeof x.status === 'number' || typeof x.getStatus === 'function')
|
|
12
12
|
return new api_exception_js_1.ApiException(response);
|
|
13
|
-
return new internal_server_error_js_1.InternalServerError(
|
|
13
|
+
return new internal_server_error_js_1.InternalServerError(response);
|
|
14
14
|
}
|
|
15
15
|
return new internal_server_error_js_1.InternalServerError();
|
|
16
16
|
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraAdapter = void 0;
|
|
4
|
+
const strict_typed_events_1 = require("strict-typed-events");
|
|
4
5
|
const i18n_1 = require("@opra/i18n");
|
|
5
6
|
const index_js_1 = require("../../exception/index.js");
|
|
6
7
|
const wrap_error_js_1 = require("../../exception/wrap-error.js");
|
|
7
8
|
class OpraAdapter {
|
|
8
9
|
service;
|
|
9
10
|
i18n;
|
|
10
|
-
|
|
11
|
+
userContextResolver;
|
|
12
|
+
constructor(service, options) {
|
|
11
13
|
this.service = service;
|
|
12
|
-
this.i18n = i18n || i18n_1.I18n.defaultInstance;
|
|
14
|
+
this.i18n = options?.i18n || i18n_1.I18n.defaultInstance;
|
|
15
|
+
this.userContextResolver = options?.userContext;
|
|
13
16
|
}
|
|
14
|
-
async handler(
|
|
17
|
+
async handler(executionContext) {
|
|
15
18
|
if (!this.i18n.isInitialized)
|
|
16
19
|
await this.i18n.init();
|
|
17
|
-
|
|
18
|
-
let requests;
|
|
20
|
+
let queryContexts;
|
|
19
21
|
let userContext;
|
|
22
|
+
let failed = false;
|
|
20
23
|
try {
|
|
21
|
-
|
|
24
|
+
queryContexts = this.prepareRequests(executionContext);
|
|
22
25
|
let stop = false;
|
|
23
26
|
// Read requests can be executed simultaneously, write request should be executed one by one
|
|
24
27
|
let promises;
|
|
25
28
|
let exclusive = false;
|
|
26
|
-
for (const
|
|
27
|
-
exclusive = exclusive ||
|
|
29
|
+
for (const context of queryContexts) {
|
|
30
|
+
exclusive = exclusive || context.query.operationType !== 'read';
|
|
28
31
|
// Wait previous read requests before executing update request
|
|
29
32
|
if (exclusive && promises) {
|
|
30
33
|
await Promise.allSettled(promises);
|
|
31
34
|
promises = undefined;
|
|
32
35
|
}
|
|
33
|
-
const resource = request.query.resource;
|
|
34
|
-
const context = this.createExecutionContext(adapterContext, request);
|
|
35
|
-
executionContexts.push(context);
|
|
36
36
|
// If previous request in bucket had an error and executed an update
|
|
37
37
|
// we do not execute next requests
|
|
38
38
|
if (stop) {
|
|
@@ -40,10 +40,14 @@ class OpraAdapter {
|
|
|
40
40
|
continue;
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
|
+
const resource = context.query.resource;
|
|
43
44
|
const promise = (async () => {
|
|
44
45
|
await resource.prepare(context);
|
|
45
|
-
if (userContextResolver && !userContext)
|
|
46
|
-
userContext =
|
|
46
|
+
if (this.userContextResolver && !userContext)
|
|
47
|
+
userContext = this.userContextResolver({
|
|
48
|
+
executionContext,
|
|
49
|
+
isBatch: this.isBatch(executionContext)
|
|
50
|
+
});
|
|
47
51
|
context.userContext = userContext;
|
|
48
52
|
await resource.execute(context);
|
|
49
53
|
})().catch(e => {
|
|
@@ -69,22 +73,21 @@ class OpraAdapter {
|
|
|
69
73
|
}
|
|
70
74
|
if (promises)
|
|
71
75
|
await Promise.allSettled(promises);
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
const hasError = !!executionContexts.find(ctx => ctx.response.errors?.length);
|
|
75
|
-
await userContext.onRequestFinish(hasError);
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
await this.sendError(adapterContext, (0, wrap_error_js_1.wrapError)(e));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
await this.sendResponse(adapterContext, executionContexts);
|
|
76
|
+
await this.sendResponse(executionContext, queryContexts);
|
|
83
77
|
}
|
|
84
78
|
catch (e) {
|
|
79
|
+
failed = true;
|
|
85
80
|
const error = (0, wrap_error_js_1.wrapError)(e);
|
|
86
|
-
await this.sendError(
|
|
87
|
-
|
|
81
|
+
await this.sendError(executionContext, error);
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
if (executionContext instanceof strict_typed_events_1.AsyncEventEmitter) {
|
|
85
|
+
await executionContext
|
|
86
|
+
.emitAsyncSerial('finish', {
|
|
87
|
+
userContext,
|
|
88
|
+
failed
|
|
89
|
+
}).catch();
|
|
90
|
+
}
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
static async initI18n(options) {
|
|
@@ -1,29 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraExpressAdapter = void 0;
|
|
4
|
+
const strict_typed_events_1 = require("strict-typed-events");
|
|
4
5
|
const url_1 = require("@opra/url");
|
|
5
6
|
const http_adapter_js_1 = require("./http-adapter.js");
|
|
6
7
|
class OpraExpressAdapter extends http_adapter_js_1.OpraHttpAdapter {
|
|
7
8
|
static async init(app, service, options) {
|
|
8
9
|
const i18n = await this.initI18n(options);
|
|
9
|
-
const adapter = new OpraExpressAdapter(service,
|
|
10
|
+
const adapter = new OpraExpressAdapter(service, {
|
|
11
|
+
...options,
|
|
12
|
+
i18n
|
|
13
|
+
});
|
|
10
14
|
const prefix = '/' + (0, url_1.normalizePath)(options?.prefix, true);
|
|
11
|
-
const userContextResolver = options?.userContext;
|
|
12
15
|
app.use(prefix, (request, response, next) => {
|
|
13
16
|
(async () => {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const adapterContext = {
|
|
17
|
-
getRequest: () => req,
|
|
18
|
-
getResponse: () => res
|
|
19
|
-
};
|
|
20
|
-
await adapter.handler(adapterContext, (isBatch) => userContextResolver && userContextResolver(request, { platform: 'express', isBatch }));
|
|
17
|
+
const executionContext = new ExpressExecutionContext(request, response);
|
|
18
|
+
await adapter.handler(executionContext);
|
|
21
19
|
})().catch(e => next(e));
|
|
22
20
|
});
|
|
23
21
|
return adapter;
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
exports.OpraExpressAdapter = OpraExpressAdapter;
|
|
25
|
+
class ExpressExecutionContext extends strict_typed_events_1.AsyncEventEmitter {
|
|
26
|
+
_request;
|
|
27
|
+
_response;
|
|
28
|
+
constructor(request, response) {
|
|
29
|
+
super();
|
|
30
|
+
this._request = new ExpressRequestWrapper(request);
|
|
31
|
+
this._response = new ExpressResponseWrapper(response);
|
|
32
|
+
}
|
|
33
|
+
getType() {
|
|
34
|
+
return 'http';
|
|
35
|
+
}
|
|
36
|
+
getPlatform() {
|
|
37
|
+
return 'express';
|
|
38
|
+
}
|
|
39
|
+
switchToHttp() {
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
getRequest() {
|
|
43
|
+
return this._request.getInstance();
|
|
44
|
+
}
|
|
45
|
+
getResponse() {
|
|
46
|
+
return this._response.getInstance();
|
|
47
|
+
}
|
|
48
|
+
getRequestWrapper() {
|
|
49
|
+
return this._request;
|
|
50
|
+
}
|
|
51
|
+
getResponseWrapper() {
|
|
52
|
+
return this._response;
|
|
53
|
+
}
|
|
54
|
+
onFinish(fn) {
|
|
55
|
+
this.on('finish', fn);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
27
58
|
class ExpressRequestWrapper {
|
|
28
59
|
instance;
|
|
29
60
|
constructor(instance) {
|
|
@@ -6,26 +6,26 @@ const constants_js_1 = require("../../constants.js");
|
|
|
6
6
|
const index_js_1 = require("../../enums/index.js");
|
|
7
7
|
const index_js_2 = require("../../exception/index.js");
|
|
8
8
|
const wrap_error_js_1 = require("../../exception/wrap-error.js");
|
|
9
|
-
const
|
|
9
|
+
const query_interface_js_1 = require("../../interfaces/query.interface.js");
|
|
10
10
|
const headers_js_1 = require("../../utils/headers.js");
|
|
11
11
|
const complex_type_js_1 = require("../data-type/complex-type.js");
|
|
12
|
-
const
|
|
12
|
+
const query_context_js_1 = require("../query-context.js");
|
|
13
13
|
const container_resource_handler_js_1 = require("../resource/container-resource-handler.js");
|
|
14
14
|
const entity_resource_handler_js_1 = require("../resource/entity-resource-handler.js");
|
|
15
15
|
const adapter_js_1 = require("./adapter.js");
|
|
16
16
|
class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
17
|
-
prepareRequests(
|
|
18
|
-
const req =
|
|
17
|
+
prepareRequests(executionContext) {
|
|
18
|
+
const req = executionContext.getRequestWrapper();
|
|
19
19
|
// todo implement batch requests
|
|
20
|
-
if (this.isBatch(
|
|
20
|
+
if (this.isBatch(executionContext)) {
|
|
21
21
|
throw new Error('not implemented yet');
|
|
22
22
|
}
|
|
23
23
|
const url = new url_1.OpraURL(req.getUrl());
|
|
24
24
|
return [
|
|
25
|
-
this.prepareRequest(
|
|
25
|
+
this.prepareRequest(executionContext, url, req.getMethod(), headers_js_1.Headers.from(req.getHeaders()), req.getBody())
|
|
26
26
|
];
|
|
27
27
|
}
|
|
28
|
-
prepareRequest(
|
|
28
|
+
prepareRequest(executionContext, url, method, headers, body) {
|
|
29
29
|
if (!url.path.size)
|
|
30
30
|
throw new index_js_2.BadRequestError();
|
|
31
31
|
if (method !== 'GET' && url.path.size > 1)
|
|
@@ -35,20 +35,13 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
35
35
|
throw new index_js_2.MethodNotAllowedError({
|
|
36
36
|
message: `Method "${method}" is not allowed by target resource`
|
|
37
37
|
});
|
|
38
|
-
return new
|
|
38
|
+
return new query_context_js_1.QueryContext({
|
|
39
|
+
service: this.service,
|
|
40
|
+
executionContext,
|
|
39
41
|
query,
|
|
40
42
|
headers,
|
|
41
43
|
params: url.searchParams,
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
createExecutionContext(adapterContext, request) {
|
|
45
|
-
return new execution_context_js_1.ExecutionContext({
|
|
46
|
-
type: 'http',
|
|
47
|
-
service: this.service,
|
|
48
|
-
request,
|
|
49
|
-
response: new execution_context_js_1.ExecutionResponse(),
|
|
50
|
-
adapterContext,
|
|
51
|
-
continueOnError: request.query.operationType === 'read'
|
|
44
|
+
continueOnError: query.operationType === 'read'
|
|
52
45
|
});
|
|
53
46
|
}
|
|
54
47
|
buildQuery(url, method, body) {
|
|
@@ -73,7 +66,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
73
66
|
switch (method) {
|
|
74
67
|
case 'GET': {
|
|
75
68
|
if (scope === 'collection') {
|
|
76
|
-
query =
|
|
69
|
+
query = query_interface_js_1.OpraQuery.forSearch(resource, {
|
|
77
70
|
filter: url.searchParams.get('$filter'),
|
|
78
71
|
limit: url.searchParams.get('$limit'),
|
|
79
72
|
skip: url.searchParams.get('$skip'),
|
|
@@ -86,7 +79,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
86
79
|
});
|
|
87
80
|
}
|
|
88
81
|
else {
|
|
89
|
-
query =
|
|
82
|
+
query = query_interface_js_1.OpraQuery.forGet(resource, p.key, {
|
|
90
83
|
pick: url.searchParams.get('$pick'),
|
|
91
84
|
omit: url.searchParams.get('$omit'),
|
|
92
85
|
include: url.searchParams.get('$include')
|
|
@@ -105,7 +98,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
105
98
|
const prop = dataType.properties?.[p.resource];
|
|
106
99
|
if (!prop)
|
|
107
100
|
throw new index_js_2.NotFoundError({ message: `Invalid or unknown resource path (${path})` });
|
|
108
|
-
const q =
|
|
101
|
+
const q = query_interface_js_1.OpraQuery.forGetProperty(prop);
|
|
109
102
|
if (nested) {
|
|
110
103
|
nested.nested = q;
|
|
111
104
|
}
|
|
@@ -119,18 +112,18 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
119
112
|
}
|
|
120
113
|
case 'DELETE': {
|
|
121
114
|
if (scope === 'collection') {
|
|
122
|
-
query =
|
|
115
|
+
query = query_interface_js_1.OpraQuery.forDeleteMany(resource, {
|
|
123
116
|
filter: url.searchParams.get('$filter'),
|
|
124
117
|
});
|
|
125
118
|
}
|
|
126
119
|
else {
|
|
127
|
-
query =
|
|
120
|
+
query = query_interface_js_1.OpraQuery.forDelete(resource, p.key);
|
|
128
121
|
}
|
|
129
122
|
break;
|
|
130
123
|
}
|
|
131
124
|
case 'POST': {
|
|
132
125
|
if (scope === 'collection') {
|
|
133
|
-
query =
|
|
126
|
+
query = query_interface_js_1.OpraQuery.forCreate(resource, body, {
|
|
134
127
|
pick: url.searchParams.get('$pick'),
|
|
135
128
|
omit: url.searchParams.get('$omit'),
|
|
136
129
|
include: url.searchParams.get('$include')
|
|
@@ -140,12 +133,12 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
140
133
|
}
|
|
141
134
|
case 'PATCH': {
|
|
142
135
|
if (scope === 'collection') {
|
|
143
|
-
query =
|
|
136
|
+
query = query_interface_js_1.OpraQuery.forUpdateMany(resource, body, {
|
|
144
137
|
filter: url.searchParams.get('$filter')
|
|
145
138
|
});
|
|
146
139
|
}
|
|
147
140
|
else {
|
|
148
|
-
query =
|
|
141
|
+
query = query_interface_js_1.OpraQuery.forUpdate(resource, p.key, body, {
|
|
149
142
|
pick: url.searchParams.get('$pick'),
|
|
150
143
|
omit: url.searchParams.get('$omit'),
|
|
151
144
|
include: url.searchParams.get('$include')
|
|
@@ -166,13 +159,13 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
166
159
|
throw new index_js_2.BadRequestError({ message: e.message });
|
|
167
160
|
}
|
|
168
161
|
}
|
|
169
|
-
async sendResponse(
|
|
162
|
+
async sendResponse(executionContext, queryContexts) {
|
|
170
163
|
const outputPackets = [];
|
|
171
|
-
for (const ctx of
|
|
164
|
+
for (const ctx of queryContexts) {
|
|
172
165
|
const v = this.createOutput(ctx);
|
|
173
166
|
outputPackets.push(v);
|
|
174
167
|
}
|
|
175
|
-
if (this.isBatch(
|
|
168
|
+
if (this.isBatch(executionContext)) {
|
|
176
169
|
// this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
|
|
177
170
|
return;
|
|
178
171
|
}
|
|
@@ -186,7 +179,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
186
179
|
});
|
|
187
180
|
}
|
|
188
181
|
const out = outputPackets[0];
|
|
189
|
-
const resp =
|
|
182
|
+
const resp = executionContext.getResponseWrapper();
|
|
190
183
|
resp.setStatus(out.status);
|
|
191
184
|
resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/json');
|
|
192
185
|
resp.setHeader(index_js_1.HttpHeaders.Cache_Control, 'no-cache');
|
|
@@ -201,11 +194,11 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
201
194
|
resp.send(JSON.stringify(out.body));
|
|
202
195
|
}
|
|
203
196
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
204
|
-
isBatch(
|
|
197
|
+
isBatch(executionContext) {
|
|
205
198
|
return false;
|
|
206
199
|
}
|
|
207
200
|
createOutput(ctx) {
|
|
208
|
-
const { query } = ctx
|
|
201
|
+
const { query } = ctx;
|
|
209
202
|
let status = ctx.response.status;
|
|
210
203
|
let body = ctx.response.value || {};
|
|
211
204
|
const errors = ctx.response.errors?.map(e => (0, wrap_error_js_1.wrapError)(e));
|
|
@@ -231,8 +224,8 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
231
224
|
body
|
|
232
225
|
};
|
|
233
226
|
}
|
|
234
|
-
async sendError(
|
|
235
|
-
const resp =
|
|
227
|
+
async sendError(executionContext, error) {
|
|
228
|
+
const resp = executionContext.getResponseWrapper();
|
|
236
229
|
resp.setStatus(error.status || 500);
|
|
237
230
|
resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/json');
|
|
238
231
|
resp.setHeader(index_js_1.HttpHeaders.Cache_Control, 'no-cache');
|