n8n-nodes-openapi-compatible 0.1.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/LICENSE.md +19 -0
- package/README.md +62 -0
- package/dist/credentials/ExampleCredentialsApi.credentials.d.ts +8 -0
- package/dist/credentials/ExampleCredentialsApi.credentials.js +46 -0
- package/dist/credentials/ExampleCredentialsApi.credentials.js.map +1 -0
- package/dist/credentials/HttpBinApi.credentials.d.ts +9 -0
- package/dist/credentials/HttpBinApi.credentials.js +43 -0
- package/dist/credentials/HttpBinApi.credentials.js.map +1 -0
- package/dist/credentials/OpenApi.credentials.d.ts +14 -0
- package/dist/credentials/OpenApi.credentials.js +71 -0
- package/dist/credentials/OpenApi.credentials.js.map +1 -0
- package/dist/nodes/ExampleNode/ExampleNode.node.d.ts +5 -0
- package/dist/nodes/ExampleNode/ExampleNode.node.js +59 -0
- package/dist/nodes/ExampleNode/ExampleNode.node.js.map +1 -0
- package/dist/nodes/HttpBin/HttpBin.node.d.ts +4 -0
- package/dist/nodes/HttpBin/HttpBin.node.js +55 -0
- package/dist/nodes/HttpBin/HttpBin.node.js.map +1 -0
- package/dist/nodes/HttpBin/HttpBin.node.json +18 -0
- package/dist/nodes/HttpBin/HttpVerbDescription.d.ts +3 -0
- package/dist/nodes/HttpBin/HttpVerbDescription.js +234 -0
- package/dist/nodes/HttpBin/HttpVerbDescription.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenAPIDescription.d.ts +3 -0
- package/dist/nodes/OpenAPINode/OpenAPIDescription.js +145 -0
- package/dist/nodes/OpenAPINode/OpenAPIDescription.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenAPIHelper.d.ts +3 -0
- package/dist/nodes/OpenAPINode/OpenAPIHelper.js +79 -0
- package/dist/nodes/OpenAPINode/OpenAPIHelper.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenAPINode.node.d.ts +10 -0
- package/dist/nodes/OpenAPINode/OpenAPINode.node.js +117 -0
- package/dist/nodes/OpenAPINode/OpenAPINode.node.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenApi.credentials.d.ts +14 -0
- package/dist/nodes/OpenAPINode/OpenApi.credentials.js +71 -0
- package/dist/nodes/OpenAPINode/OpenApi.credentials.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenApi.svg +0 -0
- package/dist/nodes/OpenAPINode/OpenApiDescription.d.ts +3 -0
- package/dist/nodes/OpenAPINode/OpenApiDescription.js +145 -0
- package/dist/nodes/OpenAPINode/OpenApiDescription.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenApiHelper.d.ts +3 -0
- package/dist/nodes/OpenAPINode/OpenApiHelper.js +156 -0
- package/dist/nodes/OpenAPINode/OpenApiHelper.js.map +1 -0
- package/dist/nodes/OpenAPINode/OpenApiNode.node.d.ts +10 -0
- package/dist/nodes/OpenAPINode/OpenApiNode.node.js +157 -0
- package/dist/nodes/OpenAPINode/OpenApiNode.node.js.map +1 -0
- package/dist/nodes/OpenAPINode/openapi.png +0 -0
- package/dist/nodes/OpenAPINode/openapi.svg +20 -0
- package/dist/package.json +67 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/index.js +0 -0
- package/package.json +65 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenApi = void 0;
|
|
4
|
+
class OpenApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'openApi';
|
|
7
|
+
this.displayName = 'OpenAPI Auth';
|
|
8
|
+
this.documentationUrl = 'https://docs.n8n.io/integrations/creating-nodes/build/credentials/';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'API Key Name',
|
|
12
|
+
name: 'apiKeyName',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: {
|
|
15
|
+
password: true,
|
|
16
|
+
},
|
|
17
|
+
default: 'X-API-Key',
|
|
18
|
+
description: 'Name of the API key header or query parameter',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
displayName: 'API Key',
|
|
22
|
+
name: 'apiKey',
|
|
23
|
+
type: 'string',
|
|
24
|
+
typeOptions: {
|
|
25
|
+
password: true,
|
|
26
|
+
},
|
|
27
|
+
default: '',
|
|
28
|
+
description: 'The API key value',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Username',
|
|
32
|
+
name: 'username',
|
|
33
|
+
type: 'string',
|
|
34
|
+
default: '',
|
|
35
|
+
description: 'Username for Basic Authentication',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
displayName: 'Password',
|
|
39
|
+
name: 'password',
|
|
40
|
+
type: 'string',
|
|
41
|
+
typeOptions: {
|
|
42
|
+
password: true,
|
|
43
|
+
},
|
|
44
|
+
default: '',
|
|
45
|
+
description: 'Password for Basic Authentication',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
displayName: 'Token',
|
|
49
|
+
name: 'token',
|
|
50
|
+
type: 'string',
|
|
51
|
+
typeOptions: {
|
|
52
|
+
password: true,
|
|
53
|
+
},
|
|
54
|
+
default: '',
|
|
55
|
+
description: 'Bearer token for Authentication',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
this.authenticate = {
|
|
59
|
+
type: 'generic',
|
|
60
|
+
properties: {},
|
|
61
|
+
};
|
|
62
|
+
this.test = {
|
|
63
|
+
request: {
|
|
64
|
+
baseURL: '={{$credentials.url}}',
|
|
65
|
+
url: '/',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.OpenApi = OpenApi;
|
|
71
|
+
//# sourceMappingURL=OpenApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApi.credentials.js","sourceRoot":"","sources":["../../../nodes/OpenAPINode/OpenApi.credentials.ts"],"names":[],"mappings":";;;AAMA,MAAa,OAAO;IAApB;QACC,SAAI,GAAG,SAAS,CAAC;QACjB,gBAAW,GAAG,cAAc,CAAC;QAC7B,qBAAgB,GAAG,oEAAoE,CAAC;QAGxF,eAAU,GAAsB;YAE/B;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,QAAQ,EAAE,IAAI;iBACd;gBACD,OAAO,EAAE,WAAW;gBACpB,WAAW,EAAE,+CAA+C;aAC5D;YACD;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,QAAQ,EAAE,IAAI;iBACd;gBACD,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mBAAmB;aAChC;YAGD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mCAAmC;aAChD;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,QAAQ,EAAE,IAAI;iBACd;gBACD,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mCAAmC;aAChD;YAGD;gBACC,WAAW,EAAE,OAAO;gBACpB,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,QAAQ,EAAE,IAAI;iBACd;gBACD,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,iCAAiC;aAC9C;SACD,CAAC;QAGF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAGX;SACD,CAAC;QAGF,SAAI,GAAmD;YACtD,OAAO,EAAE;gBACR,OAAO,EAAE,uBAAuB;gBAChC,GAAG,EAAE,GAAG;aACR;SACD,CAAC;IACH,CAAC;CAAA;AA7ED,0BA6EC"}
|
|
Binary file
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.openApiFields = exports.openApiOperations = void 0;
|
|
4
|
+
exports.openApiOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation Name or ID',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
|
10
|
+
noDataExpression: true,
|
|
11
|
+
displayOptions: {
|
|
12
|
+
show: {
|
|
13
|
+
resource: ['apiEndpoint'],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
typeOptions: {
|
|
17
|
+
loadOptionsMethod: 'loadOperations',
|
|
18
|
+
},
|
|
19
|
+
default: '',
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
exports.openApiFields = [
|
|
24
|
+
{
|
|
25
|
+
displayName: 'Parameters',
|
|
26
|
+
name: 'parameters',
|
|
27
|
+
placeholder: 'Add Parameter',
|
|
28
|
+
type: 'fixedCollection',
|
|
29
|
+
typeOptions: {
|
|
30
|
+
multipleValues: true,
|
|
31
|
+
},
|
|
32
|
+
displayOptions: {
|
|
33
|
+
show: {
|
|
34
|
+
resource: ['apiEndpoint'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
default: {},
|
|
38
|
+
options: [
|
|
39
|
+
{
|
|
40
|
+
name: 'parameter',
|
|
41
|
+
displayName: 'Parameter',
|
|
42
|
+
values: [
|
|
43
|
+
{
|
|
44
|
+
displayName: 'Name',
|
|
45
|
+
name: 'name',
|
|
46
|
+
type: 'string',
|
|
47
|
+
default: '',
|
|
48
|
+
description: 'Name of the parameter',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: 'Value',
|
|
52
|
+
name: 'value',
|
|
53
|
+
type: 'string',
|
|
54
|
+
default: '',
|
|
55
|
+
description: 'Value of the parameter',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
displayName: 'Type',
|
|
59
|
+
name: 'type',
|
|
60
|
+
type: 'options',
|
|
61
|
+
options: [
|
|
62
|
+
{
|
|
63
|
+
name: 'Query',
|
|
64
|
+
value: 'query',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Path',
|
|
68
|
+
value: 'path',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Header',
|
|
72
|
+
value: 'header',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Cookie',
|
|
76
|
+
value: 'cookie',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
default: 'query',
|
|
80
|
+
description: 'Type of the parameter',
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
description: 'Parameters to be sent',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
displayName: 'Request Body',
|
|
89
|
+
name: 'requestBody',
|
|
90
|
+
type: 'json',
|
|
91
|
+
displayOptions: {
|
|
92
|
+
show: {
|
|
93
|
+
resource: ['apiEndpoint'],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
default: '{}',
|
|
97
|
+
description: 'Request body as JSON (optional)',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
displayName: 'Options',
|
|
101
|
+
name: 'options',
|
|
102
|
+
type: 'collection',
|
|
103
|
+
placeholder: 'Add Option',
|
|
104
|
+
default: {},
|
|
105
|
+
displayOptions: {
|
|
106
|
+
show: {
|
|
107
|
+
resource: ['apiEndpoint'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
options: [
|
|
111
|
+
{
|
|
112
|
+
displayName: 'Response Format',
|
|
113
|
+
name: 'responseFormat',
|
|
114
|
+
type: 'options',
|
|
115
|
+
options: [
|
|
116
|
+
{
|
|
117
|
+
name: 'JSON',
|
|
118
|
+
value: 'json',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'String',
|
|
122
|
+
value: 'string',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Binary',
|
|
126
|
+
value: 'binary',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
default: 'json',
|
|
130
|
+
description: 'The format in which the data gets returned from the URL',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
displayName: 'Timeout',
|
|
134
|
+
name: 'timeout',
|
|
135
|
+
type: 'number',
|
|
136
|
+
typeOptions: {
|
|
137
|
+
minValue: 1,
|
|
138
|
+
},
|
|
139
|
+
default: 10000,
|
|
140
|
+
description: 'Time in ms to wait for the request to complete',
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
//# sourceMappingURL=OpenApiDescription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApiDescription.js","sourceRoot":"","sources":["../../../nodes/OpenAPINode/OpenApiDescription.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { IDataObject } from 'n8n-workflow';
|
|
2
|
+
export declare function loadOpenApiSpec(url: string): Promise<any>;
|
|
3
|
+
export declare function executeOpenApiRequest(spec: any, method: string, path: string, parameters: IDataObject, requestBody: IDataObject, credentials?: IDataObject, baseApiUrl?: string): Promise<any>;
|
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.loadOpenApiSpec = loadOpenApiSpec;
|
|
27
|
+
exports.executeOpenApiRequest = executeOpenApiRequest;
|
|
28
|
+
const yaml = __importStar(require("yaml"));
|
|
29
|
+
async function loadOpenApiSpec(url) {
|
|
30
|
+
url = url.trim();
|
|
31
|
+
if (!url) {
|
|
32
|
+
throw new Error('OpenAPI URL is empty. Please provide a valid URL.');
|
|
33
|
+
}
|
|
34
|
+
let apiUrl;
|
|
35
|
+
try {
|
|
36
|
+
apiUrl = new URL(url);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw new Error(`Invalid URL format: ${url}. Please provide a valid URL.`);
|
|
40
|
+
}
|
|
41
|
+
const response = await fetch(apiUrl.toString(), {
|
|
42
|
+
headers: {
|
|
43
|
+
'Accept': 'application/json, application/yaml, text/yaml',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new Error(`HTTP error! Status: ${response.status} - ${response.statusText}`);
|
|
48
|
+
}
|
|
49
|
+
const contentType = response.headers.get('content-type') || '';
|
|
50
|
+
const text = await response.text();
|
|
51
|
+
try {
|
|
52
|
+
if (contentType.includes('yaml') ||
|
|
53
|
+
contentType.includes('yml') ||
|
|
54
|
+
url.toLowerCase().endsWith('.yaml') ||
|
|
55
|
+
url.toLowerCase().endsWith('.yml')) {
|
|
56
|
+
return yaml.parse(text);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return JSON.parse(text);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
throw new Error(`Failed to parse response: ${error.message}. Make sure the URL returns valid JSON or YAML.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function joinURLParts(base, path) {
|
|
67
|
+
if (!base)
|
|
68
|
+
return path;
|
|
69
|
+
const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;
|
|
70
|
+
const cleanPath = path.startsWith('/') ? path : `/${path}`;
|
|
71
|
+
return `${cleanBase}${cleanPath}`;
|
|
72
|
+
}
|
|
73
|
+
async function executeOpenApiRequest(spec, method, path, parameters, requestBody, credentials, baseApiUrl) {
|
|
74
|
+
var _a;
|
|
75
|
+
let serverUrl = '';
|
|
76
|
+
if (baseApiUrl) {
|
|
77
|
+
serverUrl = baseApiUrl;
|
|
78
|
+
}
|
|
79
|
+
else if (spec.servers && spec.servers.length > 0) {
|
|
80
|
+
serverUrl = spec.servers[0].url;
|
|
81
|
+
if (serverUrl && !serverUrl.match(/^https?:\/\//)) {
|
|
82
|
+
throw new Error(`The OpenAPI spec contains a relative server URL (${serverUrl}). Please provide a base API URL in the node configuration.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!serverUrl) {
|
|
86
|
+
throw new Error('No server URL found in the OpenAPI spec and no base API URL provided. Please provide a base API URL in the node configuration.');
|
|
87
|
+
}
|
|
88
|
+
const urlPath = joinURLParts(serverUrl, path);
|
|
89
|
+
let finalUrl = urlPath;
|
|
90
|
+
if (parameters && Array.isArray(parameters.parameter)) {
|
|
91
|
+
const pathParams = parameters.parameter.filter((param) => param.type === 'path');
|
|
92
|
+
for (const param of pathParams) {
|
|
93
|
+
finalUrl = finalUrl.replace(`{${param.name}}`, param.value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const queryParams = new URLSearchParams();
|
|
97
|
+
if (parameters && Array.isArray(parameters.parameter)) {
|
|
98
|
+
const queryParamItems = parameters.parameter.filter((param) => param.type === 'query');
|
|
99
|
+
for (const param of queryParamItems) {
|
|
100
|
+
queryParams.append(param.name, param.value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const headers = {};
|
|
104
|
+
if (parameters && Array.isArray(parameters.parameter)) {
|
|
105
|
+
const headerParams = parameters.parameter.filter((param) => param.type === 'header');
|
|
106
|
+
for (const param of headerParams) {
|
|
107
|
+
headers[param.name] = param.value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (credentials && Object.keys(credentials).length > 0 && ((_a = spec.components) === null || _a === void 0 ? void 0 : _a.securitySchemes)) {
|
|
111
|
+
const apiKeyScheme = Object.values(spec.components.securitySchemes).find((scheme) => scheme.type === 'apiKey');
|
|
112
|
+
if (apiKeyScheme) {
|
|
113
|
+
const apiKeyName = apiKeyScheme.name;
|
|
114
|
+
const apiKeyValue = credentials[apiKeyName] || credentials.apiKey;
|
|
115
|
+
if (apiKeyValue) {
|
|
116
|
+
if (apiKeyScheme.in === 'header') {
|
|
117
|
+
headers[apiKeyName] = apiKeyValue;
|
|
118
|
+
}
|
|
119
|
+
else if (apiKeyScheme.in === 'query') {
|
|
120
|
+
queryParams.append(apiKeyName, apiKeyValue);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const basicAuthScheme = Object.values(spec.components.securitySchemes).find((scheme) => scheme.type === 'http' && scheme.scheme === 'basic');
|
|
125
|
+
if (basicAuthScheme && credentials.username && credentials.password) {
|
|
126
|
+
const auth = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64');
|
|
127
|
+
headers['Authorization'] = `Basic ${auth}`;
|
|
128
|
+
}
|
|
129
|
+
const bearerAuthScheme = Object.values(spec.components.securitySchemes).find((scheme) => scheme.type === 'http' && scheme.scheme === 'bearer');
|
|
130
|
+
if (bearerAuthScheme && credentials.token) {
|
|
131
|
+
headers['Authorization'] = `Bearer ${credentials.token}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const url = queryParams.toString() ? `${finalUrl}?${queryParams.toString()}` : finalUrl;
|
|
135
|
+
const methodsWithoutBody = ['GET', 'HEAD', 'DELETE', 'OPTIONS'];
|
|
136
|
+
const methodSupportsBody = !methodsWithoutBody.includes(method.toUpperCase());
|
|
137
|
+
const options = {
|
|
138
|
+
method: method.toUpperCase(),
|
|
139
|
+
headers,
|
|
140
|
+
};
|
|
141
|
+
if (methodSupportsBody && requestBody && Object.keys(requestBody).length > 0) {
|
|
142
|
+
options.body = JSON.stringify(requestBody);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const response = await fetch(url, options);
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const errorText = await response.text();
|
|
148
|
+
throw new Error(`Request failed with status code ${response.status}: ${errorText}`);
|
|
149
|
+
}
|
|
150
|
+
return await response.json();
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=OpenApiHelper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApiHelper.js","sourceRoot":"","sources":["../../../nodes/OpenAPINode/OpenApiHelper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData, ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
|
+
export declare class OpenApiNode implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
loadOptions: {
|
|
6
|
+
loadOperations(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenApiNode = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const OpenApiDescription_1 = require("./OpenApiDescription");
|
|
6
|
+
const OpenApiHelper_1 = require("./OpenApiHelper");
|
|
7
|
+
class OpenApiNode {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.description = {
|
|
10
|
+
displayName: 'OpenAPI',
|
|
11
|
+
name: 'openApiNode',
|
|
12
|
+
icon: 'file:openapi.svg',
|
|
13
|
+
group: ['transform'],
|
|
14
|
+
version: 1,
|
|
15
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
16
|
+
description: 'Consume any OpenAPI/Swagger based API',
|
|
17
|
+
defaults: {
|
|
18
|
+
name: 'OpenAPI',
|
|
19
|
+
},
|
|
20
|
+
credentials: [
|
|
21
|
+
{
|
|
22
|
+
name: 'openApi',
|
|
23
|
+
required: false,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
inputs: ["main"],
|
|
27
|
+
outputs: ["main"],
|
|
28
|
+
properties: [
|
|
29
|
+
{
|
|
30
|
+
displayName: 'OpenAPI Specification URL',
|
|
31
|
+
name: 'openApiUrl',
|
|
32
|
+
type: 'string',
|
|
33
|
+
default: '',
|
|
34
|
+
required: true,
|
|
35
|
+
description: 'URL of the OpenAPI/Swagger specification',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
displayName: 'Base API URL',
|
|
39
|
+
name: 'baseApiUrl',
|
|
40
|
+
type: 'string',
|
|
41
|
+
default: '',
|
|
42
|
+
description: 'Override the server URL from the OpenAPI specification. Use this when the spec does not provide a server URL or you need to use a different endpoint.',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
displayName: 'Resource',
|
|
46
|
+
name: 'resource',
|
|
47
|
+
type: 'options',
|
|
48
|
+
noDataExpression: true,
|
|
49
|
+
options: [
|
|
50
|
+
{
|
|
51
|
+
name: 'API Endpoint',
|
|
52
|
+
value: 'apiEndpoint',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
default: 'apiEndpoint',
|
|
56
|
+
},
|
|
57
|
+
...OpenApiDescription_1.openApiOperations,
|
|
58
|
+
...OpenApiDescription_1.openApiFields,
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
this.methods = {
|
|
62
|
+
loadOptions: {
|
|
63
|
+
async loadOperations() {
|
|
64
|
+
const openApiUrl = this.getNodeParameter('openApiUrl', 0);
|
|
65
|
+
try {
|
|
66
|
+
const spec = await (0, OpenApiHelper_1.loadOpenApiSpec)(openApiUrl);
|
|
67
|
+
const operations = [];
|
|
68
|
+
for (const path in spec.paths) {
|
|
69
|
+
for (const method in spec.paths[path]) {
|
|
70
|
+
const operation = spec.paths[path][method];
|
|
71
|
+
operations.push({
|
|
72
|
+
name: `${method.toUpperCase()} ${path} - ${operation.summary || operation.operationId || ''}`,
|
|
73
|
+
value: `${method}:${path}`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return operations;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to load OpenAPI spec: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async execute() {
|
|
87
|
+
const items = this.getInputData();
|
|
88
|
+
const returnItems = [];
|
|
89
|
+
const openApiUrl = this.getNodeParameter('openApiUrl', 0);
|
|
90
|
+
const baseApiUrl = this.getNodeParameter('baseApiUrl', 0, '');
|
|
91
|
+
let credentials = {};
|
|
92
|
+
try {
|
|
93
|
+
credentials = await this.getCredentials('openApi');
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (!(error.message && error.message.includes('does not require credentials'))) {
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const spec = await (0, OpenApiHelper_1.loadOpenApiSpec)(openApiUrl);
|
|
101
|
+
for (let i = 0; i < items.length; i++) {
|
|
102
|
+
try {
|
|
103
|
+
const operation = this.getNodeParameter('operation', i);
|
|
104
|
+
let method, path;
|
|
105
|
+
if (typeof operation === 'string') {
|
|
106
|
+
[method, path] = operation.split(':');
|
|
107
|
+
}
|
|
108
|
+
else if (typeof operation === 'object' && operation !== null) {
|
|
109
|
+
({ method, path } = operation);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid operation parameter format');
|
|
113
|
+
}
|
|
114
|
+
const parameters = this.getNodeParameter('parameters', i, {});
|
|
115
|
+
let requestBody = {};
|
|
116
|
+
const rawRequestBody = this.getNodeParameter('requestBody', i, '{}');
|
|
117
|
+
if (typeof rawRequestBody === 'string') {
|
|
118
|
+
try {
|
|
119
|
+
if (rawRequestBody.trim() !== '') {
|
|
120
|
+
requestBody = JSON.parse(rawRequestBody);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid JSON in request body: ${e.message}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
requestBody = rawRequestBody;
|
|
129
|
+
}
|
|
130
|
+
const response = await (0, OpenApiHelper_1.executeOpenApiRequest)(spec, method, path, parameters, requestBody, credentials, baseApiUrl);
|
|
131
|
+
returnItems.push({
|
|
132
|
+
json: response,
|
|
133
|
+
pairedItem: {
|
|
134
|
+
item: i,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (this.continueOnFail()) {
|
|
140
|
+
returnItems.push({
|
|
141
|
+
json: {
|
|
142
|
+
error: error.message,
|
|
143
|
+
},
|
|
144
|
+
pairedItem: {
|
|
145
|
+
item: i,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return [returnItems];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.OpenApiNode = OpenApiNode;
|
|
157
|
+
//# sourceMappingURL=OpenApiNode.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenApiNode.node.js","sourceRoot":"","sources":["../../../nodes/OpenAPINode/OpenApiNode.node.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="60" height="60">
|
|
3
|
+
<path d="M0 0 C19.8 0 39.6 0 60 0 C60 19.8 60 39.6 60 60 C40.2 60 20.4 60 0 60 C0 40.2 0 20.4 0 0 Z " fill="#FAFBF8" transform="translate(0,0)"/>
|
|
4
|
+
<path d="M0 0 C1.875 1.0625 1.875 1.0625 3 3 C3.63074205 8.8869258 3.63074205 8.8869258 1.9375 11.875 C0 13 0 13 -3.19140625 13.1875 C-8.21081934 14.25830813 -10.40102391 16.50627491 -13.875 20.125 C-14.45507812 20.681875 -15.03515625 21.23875 -15.6328125 21.8125 C-19.4787075 25.71230941 -20.66263405 28.37493909 -21 34 C-22.1875 35.9375 -22.1875 35.9375 -24 37 C-26.9375 37.5 -26.9375 37.5 -30 37 C-32.4375 34.8125 -32.4375 34.8125 -34 32 C-33.93218511 29.15177465 -33.40474006 27.62959565 -31.875 25.25 C-30 24 -30 24 -26.8125 23.8046875 C-21.78596668 22.74375936 -19.60166915 20.49653037 -16.125 16.875 C-15.54492188 16.318125 -14.96484375 15.76125 -14.3671875 15.1875 C-10.5212925 11.28769059 -9.33736595 8.62506091 -9 3 C-6.74939495 -0.67203981 -4.06250639 -0.5078133 0 0 Z " fill="#474648" transform="translate(54,3)"/>
|
|
5
|
+
<path d="M0 0 C5.75 8.21428571 5.75 8.21428571 5.75 11.5 C1.9084024 14.06780471 -2.0639175 13.72688882 -6.5 13.625 C-7.24507812 13.61597656 -7.99015625 13.60695313 -8.7578125 13.59765625 C-10.58868059 13.57418358 -12.41938238 13.53831525 -14.25 13.5 C-14.58 12.84 -14.91 12.18 -15.25 11.5 C-14.51821134 9.42803369 -13.69100997 7.3891448 -12.8125 5.375 C-12.33941406 4.27929688 -11.86632812 3.18359375 -11.37890625 2.0546875 C-11.00636719 1.21164063 -10.63382813 0.36859375 -10.25 -0.5 C-2.94230769 -1.96153846 -2.94230769 -1.96153846 0 0 Z " fill="#95D60D" transform="translate(33.25,43.5)"/>
|
|
6
|
+
<path d="M0 0 C4.62 0 9.24 0 14 0 C13.65865732 6.37173005 12.21130444 11.06713249 8 16 C7.34 16 6.68 16 6 16 C5.67 16.99 5.34 17.98 5 19 C1.38430856 17.79476952 1.05330455 16.92814436 -0.75 13.6875 C-1.19859375 12.90761719 -1.6471875 12.12773438 -2.109375 11.32421875 C-3.75602643 7.02703628 -1.68931765 4.22329412 0 0 Z " fill="#73A741" transform="translate(37,34)"/>
|
|
7
|
+
<path d="M0 0 C3.21524305 1.40844718 5.32183868 3.10344786 7.75 5.625 C8.67039062 6.57246094 8.67039062 6.57246094 9.609375 7.5390625 C10.06828125 8.02117188 10.5271875 8.50328125 11 9 C10.01 11.31 9.02 13.62 8 16 C3.38 16 -1.24 16 -6 16 C-6 9.2407932 -6 9.2407932 -3.5625 5.1875 C-3.11003906 4.41792969 -2.65757812 3.64835937 -2.19140625 2.85546875 C-1 1 -1 1 0 0 Z " fill="#4D5A2F" transform="translate(9,17)"/>
|
|
8
|
+
<path d="M0 0 C0.02685412 2.31243792 0.04632841 4.6249627 0.0625 6.9375 C0.07410156 8.22527344 0.08570313 9.51304688 0.09765625 10.83984375 C0 14 0 14 -1 15 C-3.35546875 15.3671875 -3.35546875 15.3671875 -6 15 C-7.80078125 12.8828125 -7.80078125 12.8828125 -9.3125 10.125 C-9.82425781 9.22007813 -10.33601563 8.31515625 -10.86328125 7.3828125 C-12 5 -12 5 -12 3 C-10.75336669 2.49166409 -9.50250613 1.99368855 -8.25 1.5 C-7.55390625 1.2215625 -6.8578125 0.943125 -6.140625 0.65625 C-4 0 -4 0 0 0 Z " fill="#6FA63C" transform="translate(27,9)"/>
|
|
9
|
+
<path d="M0 0 C7.875 0 7.875 0 12 3 C9.7367841 7.27496337 6.87396421 11.0642615 3 14 C2.01 14 1.02 14 0 14 C0 9.38 0 4.76 0 0 Z " fill="#525F36" transform="translate(28,10)"/>
|
|
10
|
+
<path d="M0 0 C3.3866267 4.0312661 3.5714017 6.85682038 4 12 C-0.62 12 -5.24 12 -10 12 C-8.16614077 8.33228155 -6.74937171 6.53165004 -3.875 3.75 C-3.15054688 3.04359375 -2.42609375 2.3371875 -1.6796875 1.609375 C-1.12539063 1.07828125 -0.57109375 0.5471875 0 0 Z " fill="#4E5A30" transform="translate(47,20)"/>
|
|
11
|
+
<path d="M0 0 C4.62 0 9.24 0 14 0 C12.91953754 4.32184983 12.72180502 4.64208263 9.1875 6.8125 C8.50042969 7.25207031 7.81335938 7.69164062 7.10546875 8.14453125 C4.60705494 9.15965671 3.48957835 8.91191297 1 8 C0.67 5.36 0.34 2.72 0 0 Z " fill="#93D50B" transform="translate(3,35)"/>
|
|
12
|
+
<path d="M0 0 C2.9555377 2.75170751 5.11563315 5.41970299 7 9 C7 9.66 7 10.32 7 11 C7.66 11.33 8.32 11.66 9 12 C7.26953125 12.73046875 7.26953125 12.73046875 5 13 C2.82421875 11.48828125 2.82421875 11.48828125 0.6875 9.3125 C-0.03050781 8.60738281 -0.74851562 7.90226562 -1.48828125 7.17578125 C-3 5 -3 5 -2.85546875 2.79296875 C-2 1 -2 1 0 0 Z " fill="#DAEDB6" transform="translate(14,13)"/>
|
|
13
|
+
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C0.35 5.96 -1.3 9.92 -3 14 C-5.475 13.01 -5.475 13.01 -8 12 C-8.33 11.01 -8.66 10.02 -9 9 C-8.43410156 8.51789062 -7.86820313 8.03578125 -7.28515625 7.5390625 C-6.55167969 6.90742187 -5.81820313 6.27578125 -5.0625 5.625 C-4.33160156 4.99851562 -3.60070312 4.37203125 -2.84765625 3.7265625 C-0.91619094 2.12252286 -0.91619094 2.12252286 0 0 Z " fill="#505D34" transform="translate(20,41)"/>
|
|
14
|
+
<path d="M0 0 C-1.67741664 3.96480297 -4.12126862 6.84041677 -7 10 C-7.99 10.33 -8.98 10.66 -10 11 C-10.66 9.68 -11.32 8.36 -12 7 C-10.3790787 5.82767315 -8.75313167 4.6622923 -7.125 3.5 C-6.22007813 2.8503125 -5.31515625 2.200625 -4.3828125 1.53125 C-2 0 -2 0 0 0 Z " fill="#70A63C" transform="translate(19,39)"/>
|
|
15
|
+
<path d="M0 0 C0.66 0.99 1.32 1.98 2 3 C0.23754778 4.1999038 -1.53526981 5.38459517 -3.3125 6.5625 C-4.79169922 7.55443359 -4.79169922 7.55443359 -6.30078125 8.56640625 C-7.19152344 9.03949219 -8.08226562 9.51257812 -9 10 C-9.99 9.67 -10.98 9.34 -12 9 C-9.5513959 7.04111672 -7.05317043 5.44317697 -4.3125 3.9375 C-0.96434085 2.38390486 -0.96434085 2.38390486 0 0 Z " fill="#CDE4AA" transform="translate(17,36)"/>
|
|
16
|
+
<path d="M0 0 C0.66 0.66 1.32 1.32 2 2 C1.01 3.98 0.02 5.96 -1 8 C-1.99 8 -2.98 8 -4 8 C-4.99 8.66 -5.98 9.32 -7 10 C-5.33248852 6.05860922 -2.77289351 3.2107188 0 0 Z " fill="#4A572C" transform="translate(20,41)"/>
|
|
17
|
+
<path d="M0 0 C0.66 0 1.32 0 2 0 C3.68732277 1.98260426 5.35366057 3.9832342 7 6 C7.66 6.33 8.32 6.66 9 7 C8.67 7.99 8.34 8.98 8 10 C4.30209954 8.76736651 4.0645154 7.79947549 2.3125 4.4375 C1.87550781 3.61121094 1.43851563 2.78492188 0.98828125 1.93359375 C0.66214844 1.29550781 0.33601563 0.65742187 0 0 Z " fill="#515D35" transform="translate(34,43)"/>
|
|
18
|
+
<path d="M0 0 C0.69921875 1.76953125 0.69921875 1.76953125 1 4 C-0.29296875 5.88671875 -0.29296875 5.88671875 -2.1875 7.6875 C-2.79980469 8.28949219 -3.41210938 8.89148438 -4.04296875 9.51171875 C-6.07283736 11.05539128 -7.50842901 11.58565893 -10 12 C-9.278125 11.319375 -8.55625 10.63875 -7.8125 9.9375 C-4.76544307 6.90785482 -2.42792046 3.53782696 0 0 Z " fill="#C7D0BA" transform="translate(19,39)"/>
|
|
19
|
+
<path d="M0 0 C3 1 3 1 4.75 3.4375 C5.36875 4.7059375 5.36875 4.7059375 6 6 C5.67 6.66 5.34 7.32 5 8 C3.02 5.69 1.04 3.38 -1 1 C-0.67 0.67 -0.34 0.34 0 0 Z " fill="#8FD407" transform="translate(12,14)"/>
|
|
20
|
+
</svg>
|