@trayio/cdk-runtime 1.16.0 → 2.0.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/dist/connector/operation/HttpOperationExecution.d.ts +13 -0
- package/dist/connector/operation/HttpOperationExecution.d.ts.map +1 -1
- package/dist/connector/operation/HttpOperationExecution.js +91 -11
- package/dist/connector/operation/OperationExecutionGateway.unit.test.js +7 -7
- package/package.json +4 -4
|
@@ -3,9 +3,22 @@ import { HttpOperationHandler } from '@trayio/cdk-dsl/connector/operation/HttpOp
|
|
|
3
3
|
import { HttpClient } from '@trayio/commons/http/HttpClient';
|
|
4
4
|
import { OperationExecution } from './OperationExecution';
|
|
5
5
|
export declare class HttpOperationExecution<AUTH extends OperationHandlerAuth<unknown, unknown>, IN, OUT> implements OperationExecution<AUTH, IN, OUT> {
|
|
6
|
+
private jsonSerialization;
|
|
6
7
|
private httpClient;
|
|
7
8
|
private handler;
|
|
8
9
|
constructor(httpClient: HttpClient, handler: HttpOperationHandler<AUTH, IN, OUT>);
|
|
9
10
|
execute(ctx: OperationHandlerContext<AUTH>, input: IN): Promise<OperationHandlerResult<OUT>>;
|
|
11
|
+
private operationRequestToHttpRequest;
|
|
12
|
+
private serializeAsJson;
|
|
13
|
+
private serializeAsText;
|
|
14
|
+
private serializeAsMultipart;
|
|
15
|
+
private serializeAsFile;
|
|
16
|
+
private serializeEmptyBody;
|
|
17
|
+
private defaultErrorHandling;
|
|
18
|
+
private parseResponse;
|
|
19
|
+
private parseBodyAsJson;
|
|
20
|
+
private parseEmptyBody;
|
|
21
|
+
private parseBodyAsFile;
|
|
22
|
+
private parseeBodyAsText;
|
|
10
23
|
}
|
|
11
24
|
//# sourceMappingURL=HttpOperationExecution.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpOperationExecution.d.ts","sourceRoot":"","sources":["../../../src/connector/operation/HttpOperationExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EAEtB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"HttpOperationExecution.d.ts","sourceRoot":"","sources":["../../../src/connector/operation/HttpOperationExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EAEtB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EAEN,oBAAoB,EAKpB,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAQ7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,qBAAa,sBAAsB,CAClC,IAAI,SAAS,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,EACnD,EAAE,EACF,GAAG,CACF,YAAW,kBAAkB,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC;IAE7C,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAAsC;gBAGpD,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC;IAOvC,OAAO,CACZ,GAAG,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAClC,KAAK,EAAE,EAAE,GACP,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAyCvC,OAAO,CAAC,6BAA6B;IA4BrC,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;CAQxB"}
|
|
@@ -35,25 +35,105 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
35
35
|
exports.HttpOperationExecution = void 0;
|
|
36
36
|
const OperationHandler_1 = require("@trayio/cdk-dsl/connector/operation/OperationHandler");
|
|
37
37
|
const HttpOperationHandler_1 = require("@trayio/cdk-dsl/connector/operation/HttpOperationHandler");
|
|
38
|
-
const
|
|
38
|
+
const Http_1 = require("@trayio/commons/http/Http");
|
|
39
|
+
const JsonSerialization_1 = require("@trayio/commons/serialization/JsonSerialization");
|
|
40
|
+
const TE = __importStar(require("fp-ts/TaskEither"));
|
|
41
|
+
const O = __importStar(require("fp-ts/Option"));
|
|
42
|
+
const function_1 = require("fp-ts/function");
|
|
43
|
+
const BufferExtensions_1 = require("@trayio/commons/buffer/BufferExtensions");
|
|
39
44
|
class HttpOperationExecution {
|
|
40
45
|
constructor(httpClient, handler) {
|
|
46
|
+
this.jsonSerialization = new JsonSerialization_1.JsonSerialization();
|
|
41
47
|
this.httpClient = httpClient;
|
|
42
48
|
this.handler = handler;
|
|
43
49
|
}
|
|
44
50
|
execute(ctx, input) {
|
|
45
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const operationRequest = this.handler.requestHandler(ctx, input, this.handler.request);
|
|
53
|
+
const httpRequest = this.operationRequestToHttpRequest(operationRequest);
|
|
54
|
+
const resultTE = this.httpClient.execute(operationRequest.method, operationRequest.path, httpRequest);
|
|
55
|
+
const operationResponseTE = (0, function_1.pipe)(resultTE,
|
|
56
|
+
// get the dsl http response object
|
|
57
|
+
TE.map((response) => this.handler.responseHandler(ctx, input, new HttpOperationHandler_1.HttpOperationResponseBuilder(response, this.defaultErrorHandling(response.statusCode)))),
|
|
58
|
+
// interpret the dsl response object by mapping the low level http response to a connector response
|
|
59
|
+
TE.chain((operationResponse) => this.parseResponse(operationResponse)),
|
|
60
|
+
// handle errors during the execution of the http request or parsing or the http response
|
|
61
|
+
TE.mapLeft((error) => OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.connectorError(error.message))));
|
|
62
|
+
return TE.toUnion(operationResponseTE)();
|
|
56
63
|
});
|
|
57
64
|
}
|
|
65
|
+
// TODO: Add file support, the output may need to be changed to TastEither<Error, HttpRequest>
|
|
66
|
+
operationRequestToHttpRequest(operationRequest) {
|
|
67
|
+
const serializedBody = (0, function_1.pipe)(operationRequest.contentType, O.map((contentType) => {
|
|
68
|
+
switch (contentType) {
|
|
69
|
+
case Http_1.HttpContentType.Json:
|
|
70
|
+
return this.serializeAsJson(operationRequest.body);
|
|
71
|
+
case Http_1.HttpContentType.OctetStream:
|
|
72
|
+
return this.serializeAsFile(operationRequest.body);
|
|
73
|
+
case Http_1.HttpContentType.MultipartRequestBody:
|
|
74
|
+
return this.serializeAsMultipart(operationRequest.body);
|
|
75
|
+
case Http_1.HttpContentType.Text:
|
|
76
|
+
return this.serializeAsText(operationRequest.body);
|
|
77
|
+
default:
|
|
78
|
+
return this.serializeAsJson(operationRequest.body);
|
|
79
|
+
}
|
|
80
|
+
}), O.getOrElse(() => this.serializeEmptyBody()));
|
|
81
|
+
return Object.assign(Object.assign({}, operationRequest.request), { body: serializedBody });
|
|
82
|
+
}
|
|
83
|
+
serializeAsJson(body) {
|
|
84
|
+
const serializedBody = this.jsonSerialization.serialize(body);
|
|
85
|
+
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody);
|
|
86
|
+
}
|
|
87
|
+
serializeAsText(body) {
|
|
88
|
+
const serializedBody = new TextEncoder().encode(body);
|
|
89
|
+
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody);
|
|
90
|
+
}
|
|
91
|
+
serializeAsMultipart(body) {
|
|
92
|
+
throw new Error('unimplemented');
|
|
93
|
+
}
|
|
94
|
+
serializeAsFile(body) {
|
|
95
|
+
throw new Error('unimplemented');
|
|
96
|
+
}
|
|
97
|
+
serializeEmptyBody() {
|
|
98
|
+
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(new ArrayBuffer(0));
|
|
99
|
+
}
|
|
100
|
+
defaultErrorHandling(statusCode) {
|
|
101
|
+
return () => OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.apiError(`API returned a status code of ${statusCode}`, {
|
|
102
|
+
statusCode,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
parseResponse(operationResponse) {
|
|
106
|
+
if (operationResponse.response.statusCode >= 300) {
|
|
107
|
+
return TE.right(operationResponse.errorHandling());
|
|
108
|
+
}
|
|
109
|
+
return (0, function_1.pipe)(operationResponse.contentType, O.map((contentType) => {
|
|
110
|
+
switch (contentType) {
|
|
111
|
+
case Http_1.HttpContentType.Json:
|
|
112
|
+
return this.parseBodyAsJson(operationResponse);
|
|
113
|
+
case Http_1.HttpContentType.OctetStream:
|
|
114
|
+
return this.parseBodyAsFile(operationResponse);
|
|
115
|
+
case Http_1.HttpContentType.MultipartRequestBody:
|
|
116
|
+
return TE.right(OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.connectorError(`Invalid Response Type ${contentType}`)));
|
|
117
|
+
case Http_1.HttpContentType.Text:
|
|
118
|
+
return this.parseeBodyAsText(operationResponse);
|
|
119
|
+
default:
|
|
120
|
+
return this.parseBodyAsJson(operationResponse);
|
|
121
|
+
}
|
|
122
|
+
}), O.getOrElse(() => this.parseEmptyBody(operationResponse)));
|
|
123
|
+
}
|
|
124
|
+
parseBodyAsJson(operationResponse) {
|
|
125
|
+
const deserializedBodyE = this.jsonSerialization.deserialize(operationResponse.response.body);
|
|
126
|
+
return (0, function_1.pipe)(TE.fromEither(deserializedBodyE), TE.map((deserializedBody) => operationResponse.responseParser(deserializedBody)));
|
|
127
|
+
}
|
|
128
|
+
parseEmptyBody(operationResponse) {
|
|
129
|
+
return TE.right(operationResponse.responseParser(undefined));
|
|
130
|
+
}
|
|
131
|
+
parseBodyAsFile(operationResponse) {
|
|
132
|
+
return TE.right(OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.connectorError('not implemented')));
|
|
133
|
+
}
|
|
134
|
+
parseeBodyAsText(operationResponse) {
|
|
135
|
+
const deserializeBody = new TextDecoder().decode(operationResponse.response.body);
|
|
136
|
+
return TE.right(operationResponse.responseParser(deserializeBody));
|
|
137
|
+
}
|
|
58
138
|
}
|
|
59
139
|
exports.HttpOperationExecution = HttpOperationExecution;
|
|
@@ -9,9 +9,9 @@ const getProductOperation = OperationHandlerSetup_1.OperationHandlerSetup.config
|
|
|
9
9
|
.condition((ctx, input) => input.id > 0)
|
|
10
10
|
.errorMessage(() => 'id must be bigger than zero'))
|
|
11
11
|
.usingHttp((http) => http
|
|
12
|
-
.get('https://
|
|
13
|
-
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()))
|
|
14
|
-
.handleResponse((response) => response.parseWithBodyAsJson())));
|
|
12
|
+
.get('https://jsonplaceholder.typicode.com/posts/:id')
|
|
13
|
+
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()).withoutBody())
|
|
14
|
+
.handleResponse((ctx, input, response) => response.parseWithBodyAsJson())));
|
|
15
15
|
OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(getProductOperation, (handlerTest) => handlerTest
|
|
16
16
|
.usingHandlerContext('test')
|
|
17
17
|
.nothingBeforeAll()
|
|
@@ -37,9 +37,9 @@ const getProductOperationAsText = OperationHandlerSetup_1.OperationHandlerSetup.
|
|
|
37
37
|
.condition((ctx, input) => input.id > 0)
|
|
38
38
|
.errorMessage(() => 'id must be bigger than zero'))
|
|
39
39
|
.usingHttp((http) => http
|
|
40
|
-
.get('https://
|
|
41
|
-
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()))
|
|
42
|
-
.handleResponse((response) => response.parseWithBodyAsText())));
|
|
40
|
+
.get('https://jsonplaceholder.typicode.com/posts/:id')
|
|
41
|
+
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()).withoutBody())
|
|
42
|
+
.handleResponse((ctx, input, response) => response.parseWithBodyAsText((text) => OperationHandler_1.OperationHandlerResult.success({ textField: text })))));
|
|
43
43
|
OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(getProductOperationAsText, (handlerTest) => handlerTest
|
|
44
44
|
.usingHandlerContext('test')
|
|
45
45
|
.nothingBeforeAll()
|
|
@@ -49,7 +49,7 @@ OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(getProduct
|
|
|
49
49
|
.when(() => ({ id: 2 }))
|
|
50
50
|
.then(({ output }) => {
|
|
51
51
|
const outputValue = OperationHandler_1.OperationHandlerResult.getSuccessfulValueOrFail(output);
|
|
52
|
-
expect(outputValue).toContain(`"id":2`);
|
|
52
|
+
expect(outputValue.textField).toContain(`"id": 2`);
|
|
53
53
|
})
|
|
54
54
|
.finallyDoNothing())
|
|
55
55
|
.testCase('should validate id', (testCase) => testCase
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trayio/cdk-runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A Runtime that executes connector operations defined using the CDK DSL",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./*": "./dist/*.js"
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"node": ">=18.x"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@trayio/axios": "
|
|
18
|
-
"@trayio/cdk-dsl": "
|
|
19
|
-
"@trayio/winston": "
|
|
17
|
+
"@trayio/axios": "2.0.0",
|
|
18
|
+
"@trayio/cdk-dsl": "2.0.0",
|
|
19
|
+
"@trayio/winston": "2.0.0"
|
|
20
20
|
},
|
|
21
21
|
"typesVersions": {
|
|
22
22
|
"*": {
|