@trayio/cdk-runtime 2.4.0 → 2.5.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.map +1 -1
- package/dist/connector/operation/HttpOperationExecution.js +25 -12
- package/dist/connector/operation/OperationExecutionGateway.unit.test.d.ts.map +1 -1
- package/dist/connector/operation/OperationExecutionGateway.unit.test.js +172 -56
- package/package.json +5 -4
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"HttpOperationExecution.d.ts","sourceRoot":"","sources":["../../../src/connector/operation/HttpOperationExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EAGtB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EAEN,oBAAoB,EAKpB,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAc7D,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;IAiDvC,OAAO,CAAC,6BAA6B;IA2BrC,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;CAexB"}
|
|
@@ -38,6 +38,7 @@ const HttpOperationHandler_1 = require("@trayio/cdk-dsl/connector/operation/Http
|
|
|
38
38
|
const Http_1 = require("@trayio/commons/http/Http");
|
|
39
39
|
const JsonSerialization_1 = require("@trayio/commons/serialization/JsonSerialization");
|
|
40
40
|
const TE = __importStar(require("fp-ts/TaskEither"));
|
|
41
|
+
const E = __importStar(require("fp-ts/Either"));
|
|
41
42
|
const O = __importStar(require("fp-ts/Option"));
|
|
42
43
|
const function_1 = require("fp-ts/function");
|
|
43
44
|
const BufferExtensions_1 = require("@trayio/commons/buffer/BufferExtensions");
|
|
@@ -50,8 +51,11 @@ class HttpOperationExecution {
|
|
|
50
51
|
execute(ctx, input) {
|
|
51
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
53
|
const operationRequest = this.handler.requestHandler(ctx, input, this.handler.request);
|
|
53
|
-
const
|
|
54
|
-
|
|
54
|
+
const httpRequestE = yield this.operationRequestToHttpRequest(operationRequest)();
|
|
55
|
+
if (E.isLeft(httpRequestE)) {
|
|
56
|
+
return OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.connectorError(httpRequestE.left.message));
|
|
57
|
+
}
|
|
58
|
+
const resultTE = this.httpClient.execute(operationRequest.method, operationRequest.path, httpRequestE.right);
|
|
55
59
|
const operationResponseTE = (0, function_1.pipe)(resultTE,
|
|
56
60
|
// get the dsl http response object
|
|
57
61
|
TE.map((response) => this.handler.responseHandler(ctx, input, new HttpOperationHandler_1.HttpOperationResponseBuilder(response, this.defaultErrorHandling(response.statusCode)))),
|
|
@@ -62,14 +66,13 @@ class HttpOperationExecution {
|
|
|
62
66
|
return TE.toUnion(operationResponseTE)();
|
|
63
67
|
});
|
|
64
68
|
}
|
|
65
|
-
// TODO: Add file support, the output may need to be changed to TastEither<Error, HttpRequest>
|
|
66
69
|
operationRequestToHttpRequest(operationRequest) {
|
|
67
|
-
|
|
70
|
+
return (0, function_1.pipe)(operationRequest.contentType, O.map((contentType) => {
|
|
68
71
|
switch (contentType) {
|
|
69
72
|
case Http_1.HttpContentType.Json:
|
|
70
73
|
return this.serializeAsJson(operationRequest.body);
|
|
71
74
|
case Http_1.HttpContentType.OctetStream:
|
|
72
|
-
return this.serializeAsFile(operationRequest
|
|
75
|
+
return this.serializeAsFile(operationRequest);
|
|
73
76
|
case Http_1.HttpContentType.MultipartRequestBody:
|
|
74
77
|
return this.serializeAsMultipart(operationRequest.body);
|
|
75
78
|
case Http_1.HttpContentType.Text:
|
|
@@ -77,25 +80,35 @@ class HttpOperationExecution {
|
|
|
77
80
|
default:
|
|
78
81
|
return this.serializeAsJson(operationRequest.body);
|
|
79
82
|
}
|
|
80
|
-
}), O.getOrElse(() => this.serializeEmptyBody()));
|
|
81
|
-
return Object.assign(Object.assign({}, operationRequest.request), { body: serializedBody });
|
|
83
|
+
}), O.getOrElse(() => this.serializeEmptyBody()), TE.map((serializedBody) => (Object.assign(Object.assign({}, operationRequest.request), { body: serializedBody }))));
|
|
82
84
|
}
|
|
83
85
|
serializeAsJson(body) {
|
|
84
86
|
const serializedBody = this.jsonSerialization.serialize(body);
|
|
85
|
-
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody);
|
|
87
|
+
return TE.right(BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody));
|
|
86
88
|
}
|
|
87
89
|
serializeAsText(body) {
|
|
88
90
|
const serializedBody = new TextEncoder().encode(body);
|
|
89
|
-
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody);
|
|
91
|
+
return TE.right(BufferExtensions_1.BufferExtensions.arrayBufferToReadable(serializedBody));
|
|
90
92
|
}
|
|
91
93
|
serializeAsMultipart(body) {
|
|
92
94
|
throw new Error('unimplemented');
|
|
93
95
|
}
|
|
94
|
-
serializeAsFile(
|
|
95
|
-
|
|
96
|
+
serializeAsFile(operationRequest) {
|
|
97
|
+
const downloadFilefromReference = this.httpClient.execute(Http_1.HttpMethod.Get, operationRequest.body.url, {
|
|
98
|
+
headers: { [Http_1.HttpHeader.ContentType]: Http_1.HttpContentType.OctetStream },
|
|
99
|
+
pathParams: {},
|
|
100
|
+
queryString: {},
|
|
101
|
+
body: BufferExtensions_1.BufferExtensions.arrayBufferToReadable(new ArrayBuffer(0)),
|
|
102
|
+
});
|
|
103
|
+
return (0, function_1.pipe)(downloadFilefromReference, TE.chain((response) => {
|
|
104
|
+
if (response.statusCode >= 300) {
|
|
105
|
+
return TE.left(Error('error downloading file from source'));
|
|
106
|
+
}
|
|
107
|
+
return TE.right(response.body);
|
|
108
|
+
}));
|
|
96
109
|
}
|
|
97
110
|
serializeEmptyBody() {
|
|
98
|
-
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(new ArrayBuffer(0));
|
|
111
|
+
return TE.right(BufferExtensions_1.BufferExtensions.arrayBufferToReadable(new ArrayBuffer(0)));
|
|
99
112
|
}
|
|
100
113
|
defaultErrorHandling(statusCode) {
|
|
101
114
|
return () => OperationHandler_1.OperationHandlerResult.failure(OperationHandler_1.OperationHandlerError.apiError(`API returned a status code of ${statusCode}`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationExecutionGateway.unit.test.d.ts","sourceRoot":"","sources":["../../../src/connector/operation/OperationExecutionGateway.unit.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OperationExecutionGateway.unit.test.d.ts","sourceRoot":"","sources":["../../../src/connector/operation/OperationExecutionGateway.unit.test.ts"],"names":[],"mappings":"AAIA,OAAO,8BAA8B,CAAC"}
|
|
@@ -1,62 +1,178 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
const OperationHandlerSetup_1 = require("@trayio/cdk-dsl/connector/operation/OperationHandlerSetup");
|
|
4
27
|
const OperationHandlerTest_1 = require("@trayio/cdk-dsl/connector/operation/OperationHandlerTest");
|
|
5
28
|
const OperationHandler_1 = require("@trayio/cdk-dsl/connector/operation/OperationHandler");
|
|
6
29
|
require("./OperationHandlerTestRunner");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
30
|
+
const T = __importStar(require("fp-ts/Task"));
|
|
31
|
+
const TE = __importStar(require("fp-ts/TaskEither"));
|
|
32
|
+
const function_1 = require("fp-ts/function");
|
|
33
|
+
const Http_1 = require("@trayio/commons/http/Http");
|
|
34
|
+
const stream_1 = require("stream");
|
|
35
|
+
const ExpressHttpServer_1 = require("@trayio/express/http/ExpressHttpServer");
|
|
36
|
+
const ExpressHttpController_1 = require("@trayio/express/http/ExpressHttpController");
|
|
37
|
+
const NodeFsFileStorage_1 = require("@trayio/commons/file/NodeFsFileStorage");
|
|
38
|
+
const fileStorage = new NodeFsFileStorage_1.NodeFsFileStorage('/tmp');
|
|
39
|
+
class TestControllerHttp {
|
|
40
|
+
constructor() {
|
|
41
|
+
this.getEndpoints = () => [
|
|
42
|
+
{
|
|
43
|
+
path: `/posts/:id`,
|
|
44
|
+
method: Http_1.HttpMethod.Get,
|
|
45
|
+
execute: (request) => {
|
|
46
|
+
const { id } = request.pathParams;
|
|
47
|
+
return T.of({
|
|
48
|
+
body: stream_1.Readable.from(JSON.stringify({
|
|
49
|
+
id: parseInt(id, 10),
|
|
50
|
+
title: 'test',
|
|
51
|
+
})),
|
|
52
|
+
headers: {},
|
|
53
|
+
statusCode: 200,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
path: `/image-upload`,
|
|
59
|
+
method: Http_1.HttpMethod.Post,
|
|
60
|
+
execute: (request) => {
|
|
61
|
+
const { body } = request;
|
|
62
|
+
return (0, function_1.pipe)(fileStorage.write({
|
|
63
|
+
content: body,
|
|
64
|
+
metadata: {
|
|
65
|
+
key: 'test.ico',
|
|
66
|
+
},
|
|
67
|
+
}), TE.fold(() => T.of({
|
|
68
|
+
body: stream_1.Readable.from(JSON.stringify({
|
|
69
|
+
success: false,
|
|
70
|
+
})),
|
|
71
|
+
headers: {},
|
|
72
|
+
statusCode: 500,
|
|
73
|
+
}), () => T.of({
|
|
74
|
+
body: stream_1.Readable.from(JSON.stringify({
|
|
75
|
+
success: true,
|
|
76
|
+
})),
|
|
77
|
+
headers: {},
|
|
78
|
+
statusCode: 200,
|
|
79
|
+
})));
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const testHttpController = new ExpressHttpController_1.ExpressHttpController(new TestControllerHttp(), '/tmp');
|
|
86
|
+
describe('OperationExecutionGateway', () => {
|
|
87
|
+
let server;
|
|
88
|
+
beforeAll(() => {
|
|
89
|
+
server = (0, ExpressHttpServer_1.startServer)([testHttpController], { port: 3000 });
|
|
90
|
+
});
|
|
91
|
+
afterAll(() => {
|
|
92
|
+
server.close();
|
|
93
|
+
});
|
|
94
|
+
describe('get a product', () => {
|
|
95
|
+
const getProductOperation = OperationHandlerSetup_1.OperationHandlerSetup.configureHandler((handler) => handler
|
|
96
|
+
.addInputValidation((inputValidation) => inputValidation
|
|
97
|
+
.condition((ctx, input) => input.id > 0)
|
|
98
|
+
.errorMessage(() => 'id must be bigger than zero'))
|
|
99
|
+
.usingHttp((http) => http
|
|
100
|
+
.get('http://localhost:3000/posts/:id')
|
|
101
|
+
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()).withoutBody())
|
|
102
|
+
.handleResponse((ctx, input, response) => response.parseWithBodyAsJson())));
|
|
103
|
+
OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(getProductOperation, (handlerTest) => handlerTest
|
|
104
|
+
.usingHandlerContext('test')
|
|
105
|
+
.nothingBeforeAll()
|
|
106
|
+
.testCase('should get a product', (testCase) => testCase
|
|
107
|
+
.usingHandlerContext('test')
|
|
108
|
+
.givenNothing()
|
|
109
|
+
.when(() => ({ id: 2 }))
|
|
110
|
+
.then(({ output }) => {
|
|
111
|
+
const outputValue = OperationHandler_1.OperationHandlerResult.getSuccessfulValueOrFail(output);
|
|
112
|
+
expect(outputValue.id).toEqual(2);
|
|
113
|
+
})
|
|
114
|
+
.finallyDoNothing())
|
|
115
|
+
.testCase('should validate id', (testCase) => testCase
|
|
116
|
+
.givenNothing()
|
|
117
|
+
.when(() => ({ id: -1 }))
|
|
118
|
+
.then(({ output }) => {
|
|
119
|
+
expect(output.isFailure).toBe(true);
|
|
120
|
+
})
|
|
121
|
+
.finallyDoNothing())
|
|
122
|
+
.nothingAfterAll());
|
|
123
|
+
});
|
|
124
|
+
describe('get a product as text', () => {
|
|
125
|
+
const getProductOperationAsText = OperationHandlerSetup_1.OperationHandlerSetup.configureHandler((handler) => handler
|
|
126
|
+
.addInputValidation((inputValidation) => inputValidation
|
|
127
|
+
.condition((ctx, input) => input.id > 0)
|
|
128
|
+
.errorMessage(() => 'id must be bigger than zero'))
|
|
129
|
+
.usingHttp((http) => http
|
|
130
|
+
.get('http://localhost:3000/posts/:id')
|
|
131
|
+
.handleRequest((ctx, input, request) => request.addPathParameter('id', input.id.toString()).withoutBody())
|
|
132
|
+
.handleResponse((ctx, input, response) => response.parseWithBodyAsText((text) => OperationHandler_1.OperationHandlerResult.success({ textField: text })))));
|
|
133
|
+
OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(getProductOperationAsText, (handlerTest) => handlerTest
|
|
134
|
+
.usingHandlerContext('test')
|
|
135
|
+
.nothingBeforeAll()
|
|
136
|
+
.testCase('should get a product as text', (testCase) => testCase
|
|
137
|
+
.usingHandlerContext('test')
|
|
138
|
+
.givenNothing()
|
|
139
|
+
.when(() => ({ id: 2 }))
|
|
140
|
+
.then(({ output }) => {
|
|
141
|
+
const outputValue = OperationHandler_1.OperationHandlerResult.getSuccessfulValueOrFail(output);
|
|
142
|
+
expect(outputValue.textField).toContain(`"id":2`);
|
|
143
|
+
})
|
|
144
|
+
.finallyDoNothing())
|
|
145
|
+
.testCase('should validate id', (testCase) => testCase
|
|
146
|
+
.givenNothing()
|
|
147
|
+
.when(() => ({ id: -1 }))
|
|
148
|
+
.then(({ output }) => {
|
|
149
|
+
expect(output.isFailure).toBe(true);
|
|
150
|
+
})
|
|
151
|
+
.finallyDoNothing())
|
|
152
|
+
.nothingAfterAll());
|
|
153
|
+
});
|
|
154
|
+
describe('upload an image', () => {
|
|
155
|
+
const uploadImageOperation = OperationHandlerSetup_1.OperationHandlerSetup.configureHandler((handler) => handler.usingHttp((http) => http
|
|
156
|
+
.post('http://localhost:3000/image-upload')
|
|
157
|
+
.handleRequest((ctx, input, request) => request.withBodyAsFile({
|
|
158
|
+
name: 'test-image',
|
|
159
|
+
url: 'https://tray.io/favicon.ico',
|
|
160
|
+
mime_type: 'image/png',
|
|
161
|
+
expires: 0,
|
|
162
|
+
}))
|
|
163
|
+
.handleResponse((ctx, input, response) => response.parseWithBodyAsJson())));
|
|
164
|
+
OperationHandlerTest_1.OperationHandlerTestSetup.configureHandlerTest(uploadImageOperation, (handlerTest) => handlerTest
|
|
165
|
+
.usingHandlerContext('test')
|
|
166
|
+
.nothingBeforeAll()
|
|
167
|
+
.testCase('should upload an image', (testCase) => testCase
|
|
168
|
+
.usingHandlerContext('test')
|
|
169
|
+
.givenNothing()
|
|
170
|
+
.when(() => ({}))
|
|
171
|
+
.then(({ output }) => {
|
|
172
|
+
const outputValue = OperationHandler_1.OperationHandlerResult.getSuccessfulValueOrFail(output);
|
|
173
|
+
expect(outputValue.success).toEqual(true);
|
|
174
|
+
})
|
|
175
|
+
.finallyDoNothing())
|
|
176
|
+
.nothingAfterAll());
|
|
177
|
+
});
|
|
178
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trayio/cdk-runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.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,10 @@
|
|
|
14
14
|
"node": ">=18.x"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@trayio/axios": "2.
|
|
18
|
-
"@trayio/cdk-dsl": "2.
|
|
19
|
-
"@trayio/
|
|
17
|
+
"@trayio/axios": "2.5.0",
|
|
18
|
+
"@trayio/cdk-dsl": "2.5.0",
|
|
19
|
+
"@trayio/express": "2.5.0",
|
|
20
|
+
"@trayio/winston": "2.5.0"
|
|
20
21
|
},
|
|
21
22
|
"typesVersions": {
|
|
22
23
|
"*": {
|