@opra/core 0.1.0 → 0.2.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/enums/http-headers.enum.js +3 -2
- package/cjs/implementation/adapter-utils/entity-resource-execute.util.js +36 -34
- package/cjs/implementation/adapter-utils/resource-prepare.util.js +1 -1
- package/cjs/implementation/adapter.js +14 -19
- package/cjs/implementation/express-adapter.js +3 -0
- package/cjs/implementation/headers-map.js +18 -0
- package/cjs/implementation/http-adapter.js +65 -79
- package/cjs/implementation/query-context.js +12 -19
- package/cjs/index.js +0 -2
- package/cjs/services/json-data-service.js +367 -131
- package/cjs/utils/path-to-tree.js +7 -5
- package/esm/enums/http-headers.enum.d.ts +3 -2
- package/esm/enums/http-headers.enum.js +3 -2
- package/esm/implementation/adapter-utils/entity-resource-execute.util.js +35 -33
- package/esm/implementation/adapter-utils/resource-execute.util.d.ts +2 -2
- package/esm/implementation/adapter-utils/resource-prepare.util.d.ts +2 -2
- package/esm/implementation/adapter-utils/resource-prepare.util.js +1 -1
- package/esm/implementation/adapter.d.ts +2 -2
- package/esm/implementation/adapter.js +12 -17
- package/esm/implementation/express-adapter.js +2 -0
- package/esm/implementation/headers-map.d.ts +5 -0
- package/esm/implementation/headers-map.js +14 -0
- package/esm/implementation/http-adapter.d.ts +6 -6
- package/esm/implementation/http-adapter.js +61 -75
- package/esm/implementation/query-context.d.ts +9 -15
- package/esm/implementation/query-context.js +11 -17
- package/esm/index.d.ts +0 -2
- package/esm/index.js +0 -2
- package/esm/interfaces/entity-service.interface.d.ts +8 -6
- package/esm/services/json-data-service.d.ts +56 -39
- package/esm/services/json-data-service.js +365 -129
- package/esm/types.d.ts +0 -3
- package/esm/utils/path-to-tree.d.ts +1 -1
- package/esm/utils/path-to-tree.js +7 -5
- package/i18n/en/error.json +5 -5
- package/package.json +11 -8
- package/cjs/exception/api-exception.js +0 -68
- package/cjs/exception/http-errors/bad-request.error.js +0 -26
- package/cjs/exception/http-errors/failed-dependency.error.js +0 -25
- package/cjs/exception/http-errors/forbidden.error.js +0 -27
- package/cjs/exception/http-errors/internal-server.error.js +0 -27
- package/cjs/exception/http-errors/method-not-allowed.error.js +0 -26
- package/cjs/exception/http-errors/not-acceptable.error.js +0 -26
- package/cjs/exception/http-errors/not-found.error.js +0 -29
- package/cjs/exception/http-errors/unauthorized.error.js +0 -26
- package/cjs/exception/http-errors/unprocessable-entity.error.js +0 -25
- package/cjs/exception/index.js +0 -15
- package/cjs/exception/resource-errors/resource-conflict.error.js +0 -19
- package/cjs/exception/resource-errors/resource-not-found.error.js +0 -19
- package/cjs/exception/wrap-error.js +0 -17
- package/cjs/interfaces/query.interface.js +0 -207
- package/esm/exception/api-exception.d.ts +0 -40
- package/esm/exception/api-exception.js +0 -64
- package/esm/exception/http-errors/bad-request.error.d.ts +0 -10
- package/esm/exception/http-errors/bad-request.error.js +0 -22
- package/esm/exception/http-errors/failed-dependency.error.d.ts +0 -9
- package/esm/exception/http-errors/failed-dependency.error.js +0 -21
- package/esm/exception/http-errors/forbidden.error.d.ts +0 -11
- package/esm/exception/http-errors/forbidden.error.js +0 -23
- package/esm/exception/http-errors/internal-server.error.d.ts +0 -9
- package/esm/exception/http-errors/internal-server.error.js +0 -22
- package/esm/exception/http-errors/method-not-allowed.error.d.ts +0 -10
- package/esm/exception/http-errors/method-not-allowed.error.js +0 -22
- package/esm/exception/http-errors/not-acceptable.error.d.ts +0 -10
- package/esm/exception/http-errors/not-acceptable.error.js +0 -22
- package/esm/exception/http-errors/not-found.error.d.ts +0 -13
- package/esm/exception/http-errors/not-found.error.js +0 -25
- package/esm/exception/http-errors/unauthorized.error.d.ts +0 -10
- package/esm/exception/http-errors/unauthorized.error.js +0 -22
- package/esm/exception/http-errors/unprocessable-entity.error.d.ts +0 -9
- package/esm/exception/http-errors/unprocessable-entity.error.js +0 -21
- package/esm/exception/index.d.ts +0 -12
- package/esm/exception/index.js +0 -12
- package/esm/exception/resource-errors/resource-conflict.error.d.ts +0 -4
- package/esm/exception/resource-errors/resource-conflict.error.js +0 -15
- package/esm/exception/resource-errors/resource-not-found.error.d.ts +0 -4
- package/esm/exception/resource-errors/resource-not-found.error.js +0 -15
- package/esm/exception/wrap-error.d.ts +0 -2
- package/esm/exception/wrap-error.js +0 -13
- package/esm/interfaces/query.interface.d.ts +0 -115
- package/esm/interfaces/query.interface.js +0 -203
|
@@ -8,8 +8,9 @@ exports.HttpHeaders = void 0;
|
|
|
8
8
|
var HttpHeaders;
|
|
9
9
|
(function (HttpHeaders) {
|
|
10
10
|
/* *** Custom Headers *** */
|
|
11
|
-
HttpHeaders["X_Opra_Version"] = "X-
|
|
12
|
-
HttpHeaders["X_Opra_Schema"] = "X-
|
|
11
|
+
HttpHeaders["X_Opra_Version"] = "X-Opra-Version";
|
|
12
|
+
HttpHeaders["X_Opra_Schema"] = "X-Opra-Schema";
|
|
13
|
+
HttpHeaders["X_Opra_Count"] = "X-Opra-Count";
|
|
13
14
|
/* *** Authentication *** */
|
|
14
15
|
/**
|
|
15
16
|
* Defines the authentication method that should be used to access a resource.
|
|
@@ -1,68 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.entityResourceExecute = void 0;
|
|
4
|
+
const exception_1 = require("@opra/exception");
|
|
4
5
|
const i18n_1 = require("@opra/i18n");
|
|
5
6
|
const schema_1 = require("@opra/schema");
|
|
6
7
|
const index_js_1 = require("../../enums/index.js");
|
|
7
|
-
const index_js_2 = require("../../exception/index.js");
|
|
8
|
-
const query_interface_js_1 = require("../../interfaces/query.interface.js");
|
|
9
8
|
async function entityResourceExecute(service, resource, context) {
|
|
10
9
|
const { query } = context;
|
|
11
|
-
if (
|
|
10
|
+
if (query.kind === 'SearchCollectionQuery') {
|
|
12
11
|
const promises = [];
|
|
13
12
|
let search;
|
|
14
|
-
|
|
15
|
-
promises.push(executeFn(service, resource, context, query.queryType)
|
|
13
|
+
promises.push(executeFn(service, resource, context)
|
|
16
14
|
.then(v => search = v));
|
|
17
|
-
if (query.count) {
|
|
18
|
-
|
|
19
|
-
.
|
|
15
|
+
if (query.count && resource.metadata.methods.count) {
|
|
16
|
+
const ctx = {
|
|
17
|
+
query: new schema_1.OpraCountCollectionQuery(query.resource, { filter: query.filter }),
|
|
18
|
+
resultPath: ''
|
|
19
|
+
};
|
|
20
|
+
Object.setPrototypeOf(ctx, context);
|
|
21
|
+
promises.push(executeFn(service, resource, ctx));
|
|
20
22
|
}
|
|
21
23
|
await Promise.all(promises);
|
|
22
|
-
context.response
|
|
23
|
-
...search,
|
|
24
|
-
...count
|
|
25
|
-
};
|
|
24
|
+
context.response = search;
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
28
|
-
context.response
|
|
27
|
+
context.response = await executeFn(service, resource, context);
|
|
29
28
|
}
|
|
30
29
|
exports.entityResourceExecute = entityResourceExecute;
|
|
31
|
-
async function executeFn(service, resource, context
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
async function executeFn(service, resource, context) {
|
|
31
|
+
const method = context.query.method;
|
|
32
|
+
const resolverInfo = resource.metadata.methods?.[method];
|
|
33
|
+
if (!(resolverInfo && resolverInfo.handler))
|
|
34
|
+
throw new exception_1.ForbiddenError({
|
|
35
|
+
message: (0, i18n_1.translate)('RESOLVER_FORBIDDEN', { method }, `The resource endpoint does not accept '{{method}}' operations`),
|
|
36
36
|
severity: 'error',
|
|
37
37
|
code: 'RESOLVER_FORBIDDEN'
|
|
38
38
|
});
|
|
39
39
|
let result = await resolverInfo.handler(context);
|
|
40
|
-
switch (
|
|
40
|
+
switch (method) {
|
|
41
41
|
case 'search':
|
|
42
|
-
context.response
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
42
|
+
const items = Array.isArray(result) ? result : (context.response ? [result] : []);
|
|
43
|
+
context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Schema, resource.dataType.name);
|
|
44
|
+
return items;
|
|
46
45
|
case 'get':
|
|
47
46
|
case 'update':
|
|
48
47
|
if (!result) {
|
|
49
48
|
const query = context.query;
|
|
50
|
-
throw new
|
|
49
|
+
throw new exception_1.ResourceNotFoundError(resource.name, query.keyValue);
|
|
51
50
|
}
|
|
52
51
|
break;
|
|
53
52
|
case 'count':
|
|
54
|
-
|
|
53
|
+
context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Count, result);
|
|
54
|
+
return;
|
|
55
55
|
case 'delete':
|
|
56
56
|
case 'deleteMany':
|
|
57
57
|
case 'updateMany':
|
|
58
|
-
let
|
|
58
|
+
let affected;
|
|
59
59
|
if (typeof result === 'number')
|
|
60
|
-
|
|
60
|
+
affected = result;
|
|
61
61
|
if (typeof result === 'boolean')
|
|
62
|
-
|
|
62
|
+
affected = result ? 1 : 0;
|
|
63
63
|
if (typeof result === 'object')
|
|
64
|
-
|
|
65
|
-
return {
|
|
64
|
+
affected = result.affectedRows || result.affected;
|
|
65
|
+
return {
|
|
66
|
+
operation: context.query.method,
|
|
67
|
+
affected
|
|
68
|
+
};
|
|
66
69
|
}
|
|
67
70
|
if (!result)
|
|
68
71
|
return;
|
|
@@ -76,9 +79,8 @@ async function executeFn(service, resource, context, queryType) {
|
|
|
76
79
|
result = result && typeof result === 'object' && result[field];
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
|
-
if (
|
|
80
|
-
context.
|
|
81
|
-
|
|
82
|
-
context.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, '/$schema/types/' + dataType.name);
|
|
82
|
+
if (method === 'create')
|
|
83
|
+
context.status = 201;
|
|
84
|
+
context.responseHeaders.set(index_js_1.HttpHeaders.X_Opra_Schema, resource.dataType.name);
|
|
83
85
|
return result;
|
|
84
86
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resourcePrepare = void 0;
|
|
4
4
|
async function resourcePrepare(resource, context) {
|
|
5
5
|
const { query } = context;
|
|
6
|
-
const fn = resource.metadata['pre_' + query.
|
|
6
|
+
const fn = resource.metadata['pre_' + query.method];
|
|
7
7
|
if (fn && typeof fn === 'function') {
|
|
8
8
|
await fn(context);
|
|
9
9
|
}
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraAdapter = void 0;
|
|
4
4
|
const strict_typed_events_1 = require("strict-typed-events");
|
|
5
|
+
const exception_1 = require("@opra/exception");
|
|
5
6
|
const i18n_1 = require("@opra/i18n");
|
|
6
|
-
const index_js_1 = require("../enums/index.js");
|
|
7
|
-
const index_js_2 = require("../exception/index.js");
|
|
8
|
-
const wrap_error_js_1 = require("../exception/wrap-error.js");
|
|
9
7
|
const create_i18n_js_1 = require("../utils/create-i18n.js");
|
|
10
8
|
const resource_execute_util_js_1 = require("./adapter-utils/resource-execute.util.js");
|
|
11
9
|
const resource_prepare_util_js_1 = require("./adapter-utils/resource-prepare.util.js");
|
|
@@ -40,12 +38,12 @@ class OpraAdapter {
|
|
|
40
38
|
// If previous request in bucket had an error and executed an update
|
|
41
39
|
// we do not execute next requests
|
|
42
40
|
if (stop) {
|
|
43
|
-
context.
|
|
41
|
+
context.errors.push(new exception_1.FailedDependencyError());
|
|
44
42
|
continue;
|
|
45
43
|
}
|
|
46
44
|
try {
|
|
47
45
|
const promise = (async () => {
|
|
48
|
-
if (context.query.
|
|
46
|
+
if (context.query.method === 'metadata') {
|
|
49
47
|
await this._getSchemaExecute(context);
|
|
50
48
|
return;
|
|
51
49
|
}
|
|
@@ -59,7 +57,7 @@ class OpraAdapter {
|
|
|
59
57
|
context.userContext = userContext;
|
|
60
58
|
await (0, resource_execute_util_js_1.resourceExecute)(this.service, resource, context);
|
|
61
59
|
})().catch(e => {
|
|
62
|
-
context.
|
|
60
|
+
context.errors.push(e);
|
|
63
61
|
});
|
|
64
62
|
if (exclusive)
|
|
65
63
|
await promise;
|
|
@@ -70,13 +68,13 @@ class OpraAdapter {
|
|
|
70
68
|
// todo execute sub property queries
|
|
71
69
|
}
|
|
72
70
|
catch (e) {
|
|
73
|
-
context.
|
|
71
|
+
context.errors.unshift(e);
|
|
74
72
|
}
|
|
75
|
-
if (context.
|
|
73
|
+
if (context.errors.length) {
|
|
76
74
|
// noinspection SuspiciousTypeOfGuard
|
|
77
|
-
context.
|
|
75
|
+
context.errors = context.errors.map(e => (0, exception_1.wrapException)(e));
|
|
78
76
|
if (exclusive)
|
|
79
|
-
stop = stop || !!context.
|
|
77
|
+
stop = stop || !!context.errors.find(e => !(e.issue.severity === 'warning' || e.issue.severity === 'info'));
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
if (promises)
|
|
@@ -85,7 +83,7 @@ class OpraAdapter {
|
|
|
85
83
|
}
|
|
86
84
|
catch (e) {
|
|
87
85
|
failed = true;
|
|
88
|
-
const error = (0,
|
|
86
|
+
const error = (0, exception_1.wrapException)(e);
|
|
89
87
|
await this.sendError(executionContext, error);
|
|
90
88
|
}
|
|
91
89
|
finally {
|
|
@@ -101,28 +99,25 @@ class OpraAdapter {
|
|
|
101
99
|
async _getSchemaExecute(ctx) {
|
|
102
100
|
const query = ctx.query;
|
|
103
101
|
let out;
|
|
104
|
-
if (query.resourcePath.length > 2)
|
|
105
|
-
throw new
|
|
102
|
+
if (query.resourcePath && query.resourcePath.length > 2)
|
|
103
|
+
throw new exception_1.BadRequestError();
|
|
106
104
|
if (query.resourcePath?.length) {
|
|
107
105
|
if (query.resourcePath[0] === 'resources') {
|
|
108
106
|
const resource = this.service.getResource(query.resourcePath[1]);
|
|
109
107
|
out = resource.getSchema(true);
|
|
110
108
|
query.resourcePath[1] = resource.name;
|
|
111
|
-
ctx.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + resource.kind);
|
|
112
109
|
}
|
|
113
110
|
else if (query.resourcePath[0] === 'types') {
|
|
114
111
|
const dataType = this.service.getDataType(query.resourcePath[1]);
|
|
115
112
|
out = dataType.getSchema(true);
|
|
116
113
|
query.resourcePath[1] = dataType.name;
|
|
117
|
-
ctx.response.headers.set(index_js_1.HttpHeaders.X_Opra_Schema, 'http://www.oprajs.com/reference/v1/schema#' + dataType.kind);
|
|
118
114
|
}
|
|
119
115
|
else
|
|
120
|
-
throw new
|
|
121
|
-
ctx.response
|
|
116
|
+
throw new exception_1.BadRequestError();
|
|
117
|
+
ctx.response = out;
|
|
122
118
|
return;
|
|
123
119
|
}
|
|
124
|
-
ctx.response.
|
|
125
|
-
ctx.response.value = this.service.getSchema(true);
|
|
120
|
+
ctx.response = this.service.getSchema(true);
|
|
126
121
|
}
|
|
127
122
|
static async initI18n(options) {
|
|
128
123
|
if (options?.i18n instanceof i18n_1.I18n)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraExpressAdapter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const body_parser_1 = tslib_1.__importDefault(require("body-parser"));
|
|
4
6
|
const strict_typed_events_1 = require("strict-typed-events");
|
|
5
7
|
const url_1 = require("@opra/url");
|
|
6
8
|
const http_adapter_js_1 = require("./http-adapter.js");
|
|
@@ -12,6 +14,7 @@ class OpraExpressAdapter extends http_adapter_js_1.OpraHttpAdapter {
|
|
|
12
14
|
i18n
|
|
13
15
|
});
|
|
14
16
|
const prefix = '/' + (0, url_1.normalizePath)(options?.prefix, true);
|
|
17
|
+
app.use(prefix, body_parser_1.default.json());
|
|
15
18
|
app.use(prefix, (request, response, next) => {
|
|
16
19
|
(async () => {
|
|
17
20
|
const executionContext = new ExpressExecutionContext(request, response);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HeadersMap = void 0;
|
|
4
|
+
const schema_1 = require("@opra/schema");
|
|
5
|
+
const index_js_1 = require("../enums/index.js");
|
|
6
|
+
class HeadersMap extends schema_1.ResponsiveMap {
|
|
7
|
+
constructor(data) {
|
|
8
|
+
super(data, Array.from(Object.values(index_js_1.HttpHeaders)));
|
|
9
|
+
}
|
|
10
|
+
toObject() {
|
|
11
|
+
return Array.from(this.keys()).sort()
|
|
12
|
+
.reduce((a, k) => {
|
|
13
|
+
a[k] = this.get(k);
|
|
14
|
+
return a;
|
|
15
|
+
}, {});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.HeadersMap = HeadersMap;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraHttpAdapter = void 0;
|
|
4
|
+
const exception_1 = require("@opra/exception");
|
|
4
5
|
const schema_1 = require("@opra/schema");
|
|
5
6
|
const url_1 = require("@opra/url");
|
|
6
7
|
const index_js_1 = require("../enums/index.js");
|
|
7
|
-
const index_js_2 = require("../exception/index.js");
|
|
8
|
-
const wrap_error_js_1 = require("../exception/wrap-error.js");
|
|
9
|
-
const query_interface_js_1 = require("../interfaces/query.interface.js");
|
|
10
8
|
const adapter_js_1 = require("./adapter.js");
|
|
9
|
+
const headers_map_js_1 = require("./headers-map.js");
|
|
11
10
|
const query_context_js_1 = require("./query-context.js");
|
|
12
11
|
class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
13
12
|
prepareRequests(executionContext) {
|
|
@@ -18,37 +17,37 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
18
17
|
}
|
|
19
18
|
const url = new url_1.OpraURL(req.getUrl());
|
|
20
19
|
return [
|
|
21
|
-
this.prepareRequest(executionContext, url, req.getMethod(), new
|
|
20
|
+
this.prepareRequest(executionContext, url, req.getMethod(), new headers_map_js_1.HeadersMap(req.getHeaders()), req.getBody())
|
|
22
21
|
];
|
|
23
22
|
}
|
|
24
23
|
prepareRequest(executionContext, url, method, headers, body) {
|
|
25
24
|
if (!url.path.size)
|
|
26
|
-
throw new
|
|
25
|
+
throw new exception_1.BadRequestError();
|
|
27
26
|
if (method !== 'GET' && url.path.size > 1)
|
|
28
|
-
throw new
|
|
27
|
+
throw new exception_1.BadRequestError();
|
|
29
28
|
const query = this.buildQuery(url, method, body);
|
|
30
29
|
if (!query)
|
|
31
|
-
throw new
|
|
30
|
+
throw new exception_1.MethodNotAllowedError({
|
|
32
31
|
message: `Method "${method}" is not allowed by target endpoint`
|
|
33
32
|
});
|
|
34
33
|
return new query_context_js_1.QueryContext({
|
|
35
34
|
service: this.service,
|
|
36
35
|
executionContext,
|
|
37
36
|
query,
|
|
38
|
-
headers,
|
|
37
|
+
headers: new headers_map_js_1.HeadersMap(),
|
|
39
38
|
params: url.searchParams,
|
|
40
39
|
continueOnError: query.operation === 'read'
|
|
41
40
|
});
|
|
42
41
|
}
|
|
43
|
-
|
|
42
|
+
buildGGetMetadataQuery(url) {
|
|
44
43
|
const pathLen = url.path.size;
|
|
45
44
|
const resourcePath = [];
|
|
46
45
|
let pathIndex = 0;
|
|
47
46
|
while (pathIndex < pathLen) {
|
|
48
47
|
const p = url.path.get(pathIndex++);
|
|
49
48
|
if (p.key)
|
|
50
|
-
throw new
|
|
51
|
-
if (p.resource !== '$
|
|
49
|
+
throw new exception_1.BadRequestError();
|
|
50
|
+
if (p.resource !== '$metadata') {
|
|
52
51
|
if (pathIndex === 1)
|
|
53
52
|
resourcePath.push('resources');
|
|
54
53
|
resourcePath.push(p.resource);
|
|
@@ -58,8 +57,9 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
58
57
|
pick: url.searchParams.get('$pick'),
|
|
59
58
|
omit: url.searchParams.get('$omit'),
|
|
60
59
|
include: url.searchParams.get('$include'),
|
|
60
|
+
resourcePath
|
|
61
61
|
};
|
|
62
|
-
return
|
|
62
|
+
return new schema_1.OpraGetMetadataQuery(opts);
|
|
63
63
|
}
|
|
64
64
|
buildQuery(url, method, body) {
|
|
65
65
|
let container = this.service;
|
|
@@ -68,10 +68,10 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
68
68
|
// Check if requesting metadata
|
|
69
69
|
for (let i = 0; i < pathLen; i++) {
|
|
70
70
|
const p = url.path.get(i);
|
|
71
|
-
if (p.resource === '$
|
|
71
|
+
if (p.resource === '$metadata') {
|
|
72
72
|
if (method !== 'GET')
|
|
73
73
|
return;
|
|
74
|
-
return this.
|
|
74
|
+
return this.buildGGetMetadataQuery(url);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
let pathIndex = 0;
|
|
@@ -92,7 +92,7 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
92
92
|
switch (method) {
|
|
93
93
|
case 'GET': {
|
|
94
94
|
if (scope === 'collection') {
|
|
95
|
-
query =
|
|
95
|
+
query = new schema_1.OpraSearchCollectionQuery(resource, {
|
|
96
96
|
filter: url.searchParams.get('$filter'),
|
|
97
97
|
limit: url.searchParams.get('$limit'),
|
|
98
98
|
skip: url.searchParams.get('$skip'),
|
|
@@ -105,51 +105,39 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
query =
|
|
108
|
+
query = new schema_1.OpraGetInstanceQuery(resource, p.key, {
|
|
109
109
|
pick: url.searchParams.get('$pick'),
|
|
110
110
|
omit: url.searchParams.get('$omit'),
|
|
111
111
|
include: url.searchParams.get('$include')
|
|
112
112
|
});
|
|
113
113
|
// Move through properties
|
|
114
|
-
let
|
|
115
|
-
|
|
114
|
+
let dataType = resource.dataType;
|
|
115
|
+
const curPath = [];
|
|
116
|
+
let parent = query;
|
|
116
117
|
while (pathIndex < pathLen) {
|
|
117
|
-
const dataType = nested
|
|
118
|
-
? this.service.getDataType(nested.property.type || 'string')
|
|
119
|
-
: query.resource.dataType;
|
|
120
118
|
if (!(dataType instanceof schema_1.ComplexType))
|
|
121
|
-
throw new
|
|
119
|
+
throw new TypeError(`"${resource.name}.${curPath.join()}" is not a ComplexType and has no fields.`);
|
|
122
120
|
p = url.path.get(pathIndex++);
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (nested) {
|
|
129
|
-
nested.nested = q;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
query.nested = q;
|
|
133
|
-
}
|
|
134
|
-
nested = q;
|
|
121
|
+
curPath.push(p.resource);
|
|
122
|
+
const field = dataType.getField(p.resource);
|
|
123
|
+
parent.nested = new schema_1.OpraGetFieldQuery(parent, field.name);
|
|
124
|
+
parent = parent.nested;
|
|
125
|
+
dataType = parent.dataType;
|
|
135
126
|
}
|
|
136
127
|
}
|
|
137
128
|
break;
|
|
138
129
|
}
|
|
139
130
|
case 'DELETE': {
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
query = scope === 'collection'
|
|
132
|
+
? new schema_1.OpraDeleteCollectionQuery(resource, {
|
|
142
133
|
filter: url.searchParams.get('$filter'),
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
else {
|
|
146
|
-
query = query_interface_js_1.OpraQuery.forDelete(resource, p.key);
|
|
147
|
-
}
|
|
134
|
+
})
|
|
135
|
+
: new schema_1.OpraDeleteInstanceQuery(resource, p.key);
|
|
148
136
|
break;
|
|
149
137
|
}
|
|
150
138
|
case 'POST': {
|
|
151
139
|
if (scope === 'collection') {
|
|
152
|
-
query =
|
|
140
|
+
query = new schema_1.OpraCreateInstanceQuery(resource, body, {
|
|
153
141
|
pick: url.searchParams.get('$pick'),
|
|
154
142
|
omit: url.searchParams.get('$omit'),
|
|
155
143
|
include: url.searchParams.get('$include')
|
|
@@ -158,28 +146,27 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
158
146
|
break;
|
|
159
147
|
}
|
|
160
148
|
case 'PATCH': {
|
|
161
|
-
|
|
162
|
-
|
|
149
|
+
query = scope === 'collection'
|
|
150
|
+
? new schema_1.OpraUpdateCollectionQuery(resource, body, {
|
|
163
151
|
filter: url.searchParams.get('$filter')
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
else {
|
|
167
|
-
query = query_interface_js_1.OpraQuery.forUpdate(resource, p.key, body, {
|
|
152
|
+
})
|
|
153
|
+
: new schema_1.OpraUpdateInstanceQuery(resource, p.key, body, {
|
|
168
154
|
pick: url.searchParams.get('$pick'),
|
|
169
155
|
omit: url.searchParams.get('$omit'),
|
|
170
156
|
include: url.searchParams.get('$include')
|
|
171
157
|
});
|
|
172
|
-
}
|
|
173
158
|
break;
|
|
174
159
|
}
|
|
175
160
|
}
|
|
176
161
|
return query;
|
|
177
162
|
}
|
|
178
163
|
}
|
|
179
|
-
throw new
|
|
164
|
+
throw new exception_1.InternalServerError();
|
|
180
165
|
}
|
|
181
166
|
catch (e) {
|
|
182
|
-
|
|
167
|
+
if (e instanceof exception_1.OpraException)
|
|
168
|
+
throw e;
|
|
169
|
+
throw new exception_1.BadRequestError(e);
|
|
183
170
|
}
|
|
184
171
|
}
|
|
185
172
|
async sendResponse(executionContext, queryContexts) {
|
|
@@ -192,19 +179,12 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
192
179
|
// this.writeError([], new InternalServerError({message: 'Not implemented yet'}));
|
|
193
180
|
return;
|
|
194
181
|
}
|
|
195
|
-
if (!outputPackets.length)
|
|
196
|
-
|
|
197
|
-
outputPackets.push({
|
|
198
|
-
status: err.status,
|
|
199
|
-
body: {
|
|
200
|
-
errors: [err.response]
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
182
|
+
if (!outputPackets.length)
|
|
183
|
+
return this.sendError(executionContext, new exception_1.NotFoundError());
|
|
204
184
|
const out = outputPackets[0];
|
|
205
185
|
const resp = executionContext.getResponseWrapper();
|
|
206
186
|
resp.setStatus(out.status);
|
|
207
|
-
resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/json');
|
|
187
|
+
resp.setHeader(index_js_1.HttpHeaders.Content_Type, 'application/opra+json');
|
|
208
188
|
resp.setHeader(index_js_1.HttpHeaders.Cache_Control, 'no-cache');
|
|
209
189
|
resp.setHeader(index_js_1.HttpHeaders.Pragma, 'no-cache');
|
|
210
190
|
resp.setHeader(index_js_1.HttpHeaders.Expires, '-1');
|
|
@@ -222,34 +202,35 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
222
202
|
}
|
|
223
203
|
createOutput(ctx) {
|
|
224
204
|
const { query } = ctx;
|
|
225
|
-
let
|
|
226
|
-
let
|
|
227
|
-
const errors = ctx.
|
|
205
|
+
let body;
|
|
206
|
+
let status = ctx.status || 0;
|
|
207
|
+
const errors = ctx.errors.map(e => (0, exception_1.wrapException)(e));
|
|
228
208
|
if (errors && errors.length) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
209
|
+
// Sort errors from fatal to info
|
|
210
|
+
errors.sort((a, b) => {
|
|
211
|
+
const i = exception_1.IssueSeverity.Keys.indexOf(a.issue.severity) - exception_1.IssueSeverity.Keys.indexOf(b.issue.severity);
|
|
212
|
+
if (i === 0)
|
|
213
|
+
return b.status - a.status;
|
|
214
|
+
return i;
|
|
215
|
+
});
|
|
216
|
+
if (!status || status < index_js_1.HttpStatus.BAD_REQUEST) {
|
|
217
|
+
status = errors[0].status;
|
|
234
218
|
if (status < index_js_1.HttpStatus.BAD_REQUEST)
|
|
235
219
|
status = index_js_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
236
220
|
}
|
|
237
|
-
body
|
|
221
|
+
body = {
|
|
222
|
+
operation: ctx.query.method,
|
|
223
|
+
errors: errors.map(e => e.issue)
|
|
224
|
+
};
|
|
238
225
|
}
|
|
239
226
|
else {
|
|
240
|
-
|
|
227
|
+
body = ctx.response;
|
|
241
228
|
status = status || (query.operation === 'create' ? index_js_1.HttpStatus.CREATED : index_js_1.HttpStatus.OK);
|
|
242
229
|
}
|
|
243
|
-
// Convert headers map to object
|
|
244
|
-
const headers = Array.from(ctx.response.headers.keys()).map(k => k.toLowerCase()).sort()
|
|
245
|
-
.reduce((a, k) => {
|
|
246
|
-
a[k] = ctx.response.headers.get(k);
|
|
247
|
-
return a;
|
|
248
|
-
}, {});
|
|
249
230
|
body = this.i18n.deep(body);
|
|
250
231
|
return {
|
|
251
232
|
status,
|
|
252
|
-
headers,
|
|
233
|
+
headers: ctx.responseHeaders.toObject(),
|
|
253
234
|
body
|
|
254
235
|
};
|
|
255
236
|
}
|
|
@@ -261,7 +242,12 @@ class OpraHttpAdapter extends adapter_js_1.OpraAdapter {
|
|
|
261
242
|
resp.setHeader(index_js_1.HttpHeaders.Pragma, 'no-cache');
|
|
262
243
|
resp.setHeader(index_js_1.HttpHeaders.Expires, '-1');
|
|
263
244
|
resp.setHeader(index_js_1.HttpHeaders.X_Opra_Version, schema_1.OpraSchema.Version);
|
|
264
|
-
|
|
245
|
+
const issue = this.i18n.deep(error.issue);
|
|
246
|
+
const body = {
|
|
247
|
+
operation: 'unknown',
|
|
248
|
+
errors: [issue]
|
|
249
|
+
};
|
|
250
|
+
resp.send(JSON.stringify(body));
|
|
265
251
|
}
|
|
266
252
|
}
|
|
267
253
|
exports.OpraHttpAdapter = OpraHttpAdapter;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const schema_1 = require("@opra/schema");
|
|
3
|
+
exports.QueryContext = void 0;
|
|
5
4
|
const url_1 = require("@opra/url");
|
|
6
|
-
const
|
|
5
|
+
const headers_map_js_1 = require("./headers-map.js");
|
|
7
6
|
class QueryContext {
|
|
8
7
|
service;
|
|
9
8
|
executionContext;
|
|
@@ -12,14 +11,21 @@ class QueryContext {
|
|
|
12
11
|
headers;
|
|
13
12
|
parentValue;
|
|
14
13
|
resultPath;
|
|
14
|
+
responseHeaders;
|
|
15
15
|
response;
|
|
16
|
+
errors = [];
|
|
17
|
+
status;
|
|
16
18
|
userContext;
|
|
17
19
|
continueOnError;
|
|
18
20
|
constructor(args) {
|
|
19
|
-
Object.assign(this, args);
|
|
20
|
-
this.
|
|
21
|
+
// Object.assign(this, args);
|
|
22
|
+
this.service = args.service;
|
|
23
|
+
this.executionContext = args.executionContext;
|
|
24
|
+
this.query = args.query;
|
|
25
|
+
// this.response = new QueryResponse();
|
|
21
26
|
this.params = this.params || new url_1.OpraURLSearchParams();
|
|
22
|
-
this.headers =
|
|
27
|
+
this.headers = new headers_map_js_1.HeadersMap(args.headers);
|
|
28
|
+
this.responseHeaders = new headers_map_js_1.HeadersMap();
|
|
23
29
|
this.resultPath = this.resultPath || '';
|
|
24
30
|
}
|
|
25
31
|
get type() {
|
|
@@ -32,16 +38,3 @@ class QueryContext {
|
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
exports.QueryContext = QueryContext;
|
|
35
|
-
class QueryResponse {
|
|
36
|
-
headers;
|
|
37
|
-
errors = [];
|
|
38
|
-
status;
|
|
39
|
-
value;
|
|
40
|
-
total;
|
|
41
|
-
constructor(args) {
|
|
42
|
-
if (args)
|
|
43
|
-
Object.assign(this, args);
|
|
44
|
-
this.headers = new schema_1.ResponsiveMap(undefined, Array.from(Object.values(index_js_1.HttpHeaders)));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
exports.QueryResponse = QueryResponse;
|
package/cjs/index.js
CHANGED
|
@@ -4,9 +4,7 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
require("reflect-metadata");
|
|
5
5
|
tslib_1.__exportStar(require("./types.js"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./enums/index.js"), exports);
|
|
7
|
-
tslib_1.__exportStar(require("./exception/index.js"), exports);
|
|
8
7
|
tslib_1.__exportStar(require("./interfaces/execution-context.interface.js"), exports);
|
|
9
|
-
tslib_1.__exportStar(require("./interfaces/query.interface.js"), exports);
|
|
10
8
|
tslib_1.__exportStar(require("./interfaces/entity-service.interface.js"), exports);
|
|
11
9
|
tslib_1.__exportStar(require("./implementation/query-context.js"), exports);
|
|
12
10
|
tslib_1.__exportStar(require("./implementation/adapter.js"), exports);
|