arazzo-runner 0.0.7 → 0.0.8
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/README.md +16 -8
- package/package.json +2 -1
- package/src/Arazzo.js +53 -66
- package/src/OpenAPI.js +48 -10
package/README.md
CHANGED
|
@@ -63,6 +63,18 @@ jq --arg password "$secret_password" '.workflowId1.password = $password' input.j
|
|
|
63
63
|
|
|
64
64
|
Obviously, if you have a lot of secret variables that need adding as inputs, then you might need to write a script that can alter the `input.json` file for you within your CI/CD runner.
|
|
65
65
|
|
|
66
|
+
## OpenAPI Servers
|
|
67
|
+
|
|
68
|
+
OpenAPI Documents allow you to specify servers at the root, [path](https://spec.openapis.org/oas/latest.html#path-item-object) and [operation](https://spec.openapis.org/oas/latest.html#operation-object) level. They allow you to specify multiple servers, however the OpenAPI specification is opinionated that all servers specified in a Document should return the same thing.
|
|
69
|
+
|
|
70
|
+
This Arazzo Runner will pick the first server it comes across in the array of servers and run the operation against that.
|
|
71
|
+
|
|
72
|
+
- If the operation has servers specified, it will use the first server at the operation level, ignoring path and root servers.
|
|
73
|
+
- If the operation does not have a server specified, and the path level does, it will use the path level server, ignoring the root level
|
|
74
|
+
- If the operation only has servers specified at the root of the document, it will only use the first root level server.
|
|
75
|
+
|
|
76
|
+
It will attempt to map to the [Server Variables](https://spec.openapis.org/oas/latest.html#server-variable-object), using the `default` that is set.
|
|
77
|
+
|
|
66
78
|
## OpenAPI Parameters
|
|
67
79
|
|
|
68
80
|
OpenAPI Documents allow you to specify [`header`, `path` and `query` parameters](https://spec.openapis.org/oas/latest.html#parameter-object) in myriad of styles. This Arazzo Runner will respect your styling and send the format to the server as specified by your OpenAPI document.
|
|
@@ -99,17 +111,13 @@ Work on Reporting still needs completeing.
|
|
|
99
111
|
|
|
100
112
|
## Still unsupported
|
|
101
113
|
|
|
102
|
-
###
|
|
114
|
+
### Security
|
|
103
115
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
### OpenAPI Servers on various levels
|
|
107
|
-
|
|
108
|
-
This pulls from the top level servers object of an OpenAPI Document. Server variables do not work either.
|
|
116
|
+
OpenAPI security is still not fully supported
|
|
109
117
|
|
|
110
|
-
###
|
|
118
|
+
### PathOperation
|
|
111
119
|
|
|
112
|
-
OpenAPI
|
|
120
|
+
Accessing an OpenAPI operation by Operation Path `'{$sourceDescriptions.petstoreDescription.url}#/paths/~1pet~1findByStatus/get'` does not work currently
|
|
113
121
|
|
|
114
122
|
### JSONPath and XPath criteria objects
|
|
115
123
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arazzo-runner",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "A runner to run through Arazzo Document workflows",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"ajv": "^8.17.1",
|
|
43
43
|
"jsonpath": "^1.1.1",
|
|
44
44
|
"openapi-params": "^0.0.5",
|
|
45
|
+
"openapi-server-url-templating": "^1.3.0",
|
|
45
46
|
"stream-chain": "^3.4.0",
|
|
46
47
|
"stream-json": "^1.9.1"
|
|
47
48
|
}
|
package/src/Arazzo.js
CHANGED
|
@@ -210,8 +210,6 @@ class Arazzo extends Document {
|
|
|
210
210
|
|
|
211
211
|
this.logger.notice(`Running Step: ${step.stepId}`);
|
|
212
212
|
|
|
213
|
-
// need to deal with reloading the rules when in a retry state or a goto state
|
|
214
|
-
// if (this.stepContext?.[step.stepId]?.hasLoadedRules === false) {
|
|
215
213
|
if (this.step.onSuccess) {
|
|
216
214
|
rules.setSuccessRules(this.step.onSuccess);
|
|
217
215
|
// this.workflow.rules.setStepSuccesses(this.step.onSuccess);
|
|
@@ -224,10 +222,6 @@ class Arazzo extends Document {
|
|
|
224
222
|
|
|
225
223
|
rules.combineRules(this.workflow.rules);
|
|
226
224
|
this.step.rules = rules;
|
|
227
|
-
// this.step.rules.combineRules(this.workflow.rules);
|
|
228
|
-
|
|
229
|
-
// this.stepContext[step.stepId].hasLoadedRules = true;
|
|
230
|
-
// }
|
|
231
225
|
|
|
232
226
|
await this.loadOperationData();
|
|
233
227
|
|
|
@@ -253,7 +247,7 @@ class Arazzo extends Document {
|
|
|
253
247
|
* @private
|
|
254
248
|
*/
|
|
255
249
|
async runOpenAPIStep() {
|
|
256
|
-
this.
|
|
250
|
+
this.operation = await this.sourceDescriptionFile.buildOperation(
|
|
257
251
|
this.inputs,
|
|
258
252
|
this.step,
|
|
259
253
|
);
|
|
@@ -307,50 +301,48 @@ class Arazzo extends Document {
|
|
|
307
301
|
}
|
|
308
302
|
};
|
|
309
303
|
|
|
310
|
-
|
|
311
|
-
let url = operation.url;
|
|
304
|
+
let url = this.operation.url;
|
|
312
305
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
if (this.operation.queryParams.size) {
|
|
307
|
+
url += `?${this.operation.queryParams}`;
|
|
308
|
+
}
|
|
316
309
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
310
|
+
const options = {
|
|
311
|
+
method: this.operation.method,
|
|
312
|
+
headers: this.operation.headers,
|
|
313
|
+
};
|
|
321
314
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
315
|
+
if (this.operation.data) {
|
|
316
|
+
options.body = this.operation.data;
|
|
317
|
+
}
|
|
325
318
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
319
|
+
if (this.retryAfter) {
|
|
320
|
+
this.logger.notice(
|
|
321
|
+
`retryAfter was set: waiting ${this.retryAfter * 1000} seconds`,
|
|
322
|
+
);
|
|
323
|
+
await sleep(this.retryAfter * 1000);
|
|
324
|
+
}
|
|
332
325
|
|
|
333
|
-
|
|
334
|
-
|
|
326
|
+
this.expression.addToContext("url", url);
|
|
327
|
+
this.expression.addToContext("method", options.method);
|
|
335
328
|
|
|
336
|
-
|
|
329
|
+
this.logger.notice(`Making a ${options.method.toUpperCase()} to ${url}`);
|
|
337
330
|
|
|
338
|
-
|
|
331
|
+
const response = await fetch(url, options);
|
|
339
332
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
333
|
+
if (response.headers.has("retry-after")) {
|
|
334
|
+
const retryAfter = parseRetryAfter(response.headers.get("retry-after"));
|
|
335
|
+
if (retryAfter !== null) {
|
|
336
|
+
this.retryAfter = retryAfter;
|
|
345
337
|
}
|
|
338
|
+
}
|
|
346
339
|
|
|
347
|
-
|
|
348
|
-
|
|
340
|
+
this.addParamsToContext(response.headers, "header", "response");
|
|
341
|
+
this.expression.addToContext("statusCode", response.status);
|
|
349
342
|
|
|
350
|
-
|
|
343
|
+
this.logger.notice(`${url} responded with a: ${response.status}`);
|
|
351
344
|
|
|
352
|
-
|
|
353
|
-
}
|
|
345
|
+
await this.dealWithResponse(response);
|
|
354
346
|
}
|
|
355
347
|
|
|
356
348
|
/**
|
|
@@ -725,10 +717,8 @@ class Arazzo extends Document {
|
|
|
725
717
|
this.mapParameters();
|
|
726
718
|
this.mapRequestBody();
|
|
727
719
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
this.addParamsToContext(operation.queryParams, "query", "request");
|
|
731
|
-
}
|
|
720
|
+
this.addParamsToContext(this.operation.headers, "headers", "request");
|
|
721
|
+
this.addParamsToContext(this.operation.queryParams, "query", "request");
|
|
732
722
|
}
|
|
733
723
|
|
|
734
724
|
/**
|
|
@@ -765,19 +755,18 @@ class Arazzo extends Document {
|
|
|
765
755
|
break;
|
|
766
756
|
|
|
767
757
|
case "path":
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
// operation.url = operation.url.replace(`{${param.name}}`, value);
|
|
779
|
-
// Object.assign(pathParams, { [param.name]: value });
|
|
758
|
+
const pathStyle = operationDetailParam?.style || "simple";
|
|
759
|
+
const pathExplode = operationDetailParam?.explode || false;
|
|
760
|
+
|
|
761
|
+
pathParams.append(param.name, value, {
|
|
762
|
+
style: pathStyle,
|
|
763
|
+
explode: pathExplode,
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
for (const [name, value] of pathParams.entries()) {
|
|
767
|
+
this.operation.url = this.operation.url.replace(`{${name}}`, value);
|
|
780
768
|
}
|
|
769
|
+
|
|
781
770
|
break;
|
|
782
771
|
|
|
783
772
|
case "query":
|
|
@@ -801,12 +790,9 @@ class Arazzo extends Document {
|
|
|
801
790
|
}
|
|
802
791
|
|
|
803
792
|
this.addParamsToContext(pathParams, "path", "request");
|
|
804
|
-
// this.expression.addToContext("request.path", pathParams);
|
|
805
793
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
operation.queryParams = queryParams;
|
|
809
|
-
}
|
|
794
|
+
this.operation.headers = headersObj;
|
|
795
|
+
this.operation.queryParams = queryParams;
|
|
810
796
|
}
|
|
811
797
|
|
|
812
798
|
/**
|
|
@@ -833,13 +819,14 @@ class Arazzo extends Document {
|
|
|
833
819
|
this.step.requestBody.payload,
|
|
834
820
|
);
|
|
835
821
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
operation.data = payload;
|
|
822
|
+
if (this.step.requestBody.contentType) {
|
|
823
|
+
this.operation.headers.append(
|
|
824
|
+
"accept",
|
|
825
|
+
this.step.requestBody.contentType,
|
|
826
|
+
);
|
|
842
827
|
}
|
|
828
|
+
|
|
829
|
+
this.operation.data = payload;
|
|
843
830
|
}
|
|
844
831
|
}
|
|
845
832
|
|
package/src/OpenAPI.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const { substitute, parse } = require("openapi-server-url-templating");
|
|
4
|
+
|
|
3
5
|
const Document = require("./Document");
|
|
4
6
|
|
|
5
7
|
class OpenAPI extends Document {
|
|
@@ -17,8 +19,9 @@ class OpenAPI extends Document {
|
|
|
17
19
|
for (let operation in value[key]) {
|
|
18
20
|
if (value[key][operation]?.operationId === operationId) {
|
|
19
21
|
this.path = key;
|
|
20
|
-
this.
|
|
22
|
+
this.method = operation;
|
|
21
23
|
this.operationDetails = value[key][operation];
|
|
24
|
+
this.pathServers = value[key]?.["servers"] || [];
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -30,11 +33,19 @@ class OpenAPI extends Document {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
async buildOperation(inputs, step) {
|
|
33
|
-
|
|
36
|
+
if (!this.pathServers.length && !this.operationDetails?.servers?.length) {
|
|
37
|
+
await this.getServers();
|
|
38
|
+
} else {
|
|
39
|
+
if (this.operationDetails.servers) {
|
|
40
|
+
this.servers = this.operationDetails.servers;
|
|
41
|
+
} else {
|
|
42
|
+
this.servers = this.pathServers;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
|
|
35
46
|
this.buildOperations();
|
|
36
47
|
|
|
37
|
-
return this.
|
|
48
|
+
return this.operation;
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
async getServers() {
|
|
@@ -65,15 +76,42 @@ class OpenAPI extends Document {
|
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
parseServer() {
|
|
80
|
+
const server = this.servers.at(0);
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
if (server.variables) {
|
|
83
|
+
const parseResult = parse(server.url);
|
|
84
|
+
const parts = [];
|
|
85
|
+
|
|
86
|
+
parseResult.ast.translate(parts);
|
|
87
|
+
|
|
88
|
+
for (const partType of parts) {
|
|
89
|
+
const [type, value] = partType;
|
|
90
|
+
|
|
91
|
+
if (type === "server-variable-name") {
|
|
92
|
+
const replacementValueData = server.variables[value];
|
|
93
|
+
if (replacementValueData.default) {
|
|
94
|
+
server.url = server.url.replace(
|
|
95
|
+
`{${value}}`,
|
|
96
|
+
replacementValueData.default,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
76
101
|
}
|
|
102
|
+
|
|
103
|
+
return server;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
buildOperations() {
|
|
107
|
+
this.operation = {};
|
|
108
|
+
|
|
109
|
+
const server = this.parseServer();
|
|
110
|
+
|
|
111
|
+
Object.assign(this.operation, {
|
|
112
|
+
url: `${server.url}${this.path}`,
|
|
113
|
+
method: this.method,
|
|
114
|
+
});
|
|
77
115
|
}
|
|
78
116
|
}
|
|
79
117
|
|