api 4.5.1 → 5.0.0-beta.2
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 +1 -1
- package/README.md +32 -162
- package/bin/api +2 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +91 -0
- package/dist/cache.d.ts +30 -0
- package/dist/cache.js +217 -0
- package/dist/cli/codegen/index.d.ts +4 -0
- package/dist/cli/codegen/index.js +23 -0
- package/dist/cli/codegen/language.d.ts +27 -0
- package/dist/cli/codegen/language.js +19 -0
- package/dist/cli/codegen/languages/typescript.d.ts +99 -0
- package/dist/cli/codegen/languages/typescript.js +769 -0
- package/dist/cli/commands/index.d.ts +4 -0
- package/dist/cli/commands/index.js +9 -0
- package/dist/cli/commands/install.d.ts +3 -0
- package/dist/cli/commands/install.js +230 -0
- package/dist/cli/lib/prompt.d.ts +9 -0
- package/dist/cli/lib/prompt.js +81 -0
- package/dist/cli/logger.d.ts +1 -0
- package/dist/cli/logger.js +16 -0
- package/dist/cli/storage.d.ts +105 -0
- package/dist/cli/storage.js +264 -0
- package/dist/core/getJSONSchemaDefaults.d.ts +15 -0
- package/dist/core/getJSONSchemaDefaults.js +62 -0
- package/dist/core/index.d.ts +32 -0
- package/dist/core/index.js +143 -0
- package/dist/core/parseResponse.d.ts +1 -0
- package/dist/core/parseResponse.js +65 -0
- package/dist/core/prepareAuth.d.ts +5 -0
- package/dist/core/prepareAuth.js +55 -0
- package/dist/core/prepareParams.d.ts +24 -0
- package/dist/core/prepareParams.js +351 -0
- package/dist/core/prepareServer.d.ts +13 -0
- package/dist/core/prepareServer.js +50 -0
- package/dist/fetcher.d.ts +54 -0
- package/dist/fetcher.js +165 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +276 -0
- package/dist/packageInfo.d.ts +2 -0
- package/dist/packageInfo.js +6 -0
- package/package.json +67 -28
- package/src/.sink.d.ts +1 -0
- package/src/bin.ts +20 -0
- package/src/cache.ts +212 -0
- package/src/cli/codegen/index.ts +31 -0
- package/src/cli/codegen/language.ts +47 -0
- package/src/cli/codegen/languages/typescript.ts +807 -0
- package/src/cli/commands/index.ts +5 -0
- package/src/cli/commands/install.ts +196 -0
- package/src/cli/lib/prompt.ts +29 -0
- package/src/cli/logger.ts +10 -0
- package/src/cli/storage.ts +297 -0
- package/src/core/getJSONSchemaDefaults.ts +74 -0
- package/src/core/index.ts +108 -0
- package/src/{lib/parseResponse.js → core/parseResponse.ts} +5 -7
- package/src/core/prepareAuth.ts +85 -0
- package/src/core/prepareParams.ts +338 -0
- package/src/{lib/prepareServer.js → core/prepareServer.ts} +13 -12
- package/src/fetcher.ts +141 -0
- package/src/index.ts +212 -0
- package/src/packageInfo.ts +3 -0
- package/src/typings.d.ts +3 -0
- package/tsconfig.json +24 -0
- package/src/cache.js +0 -225
- package/src/index.js +0 -177
- package/src/lib/getSchema.js +0 -34
- package/src/lib/index.js +0 -11
- package/src/lib/prepareAuth.js +0 -69
- package/src/lib/prepareParams.js +0 -198
package/src/index.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
const fetch = require('node-fetch');
|
|
2
|
-
const fetchHar = require('fetch-har');
|
|
3
|
-
const Oas = require('oas').default;
|
|
4
|
-
const oasToHar = require('@readme/oas-to-har');
|
|
5
|
-
const pkg = require('../package.json');
|
|
6
|
-
|
|
7
|
-
const Cache = require('./cache');
|
|
8
|
-
const { parseResponse, prepareAuth, prepareParams, prepareServer } = require('./lib');
|
|
9
|
-
|
|
10
|
-
global.fetch = fetch;
|
|
11
|
-
global.Request = fetch.Request;
|
|
12
|
-
global.Headers = fetch.Headers;
|
|
13
|
-
global.FormData = require('form-data');
|
|
14
|
-
|
|
15
|
-
class Sdk {
|
|
16
|
-
constructor(uri, opts = {}) {
|
|
17
|
-
this.uri = uri;
|
|
18
|
-
this.userAgent = `${pkg.name} (node)/${pkg.version}`;
|
|
19
|
-
|
|
20
|
-
this.cacheDir = opts.cacheDir ? opts.cacheDir : false;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static getOperations(spec) {
|
|
24
|
-
return Object.keys(spec.api.paths)
|
|
25
|
-
.map(path => {
|
|
26
|
-
return Object.keys(spec.api.paths[path]).map(method => {
|
|
27
|
-
return spec.operation(path, method);
|
|
28
|
-
});
|
|
29
|
-
})
|
|
30
|
-
.reduce((prev, next) => prev.concat(next), []);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
load() {
|
|
34
|
-
let authKeys = [];
|
|
35
|
-
const cache = new Cache(this.uri, this.cacheDir);
|
|
36
|
-
const self = this;
|
|
37
|
-
let config = { parseResponse: true };
|
|
38
|
-
let server = false;
|
|
39
|
-
|
|
40
|
-
let isLoaded = false;
|
|
41
|
-
let isCached = cache.isCached();
|
|
42
|
-
let sdk = {};
|
|
43
|
-
|
|
44
|
-
function fetchOperation(spec, operation, body, metadata) {
|
|
45
|
-
return new Promise(resolve => {
|
|
46
|
-
resolve(prepareParams(operation, body, metadata));
|
|
47
|
-
}).then(params => {
|
|
48
|
-
const data = { ...params };
|
|
49
|
-
|
|
50
|
-
// If `sdk.server()` has been issued data then we need to do some extra work to figure out how to use that
|
|
51
|
-
// supplied server, and also handle any server variables that were sent alongside it.
|
|
52
|
-
if (server) {
|
|
53
|
-
const preparedServer = prepareServer(spec, server.url, server.variables);
|
|
54
|
-
if (preparedServer) {
|
|
55
|
-
data.server = preparedServer;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const har = oasToHar(spec, operation, data, prepareAuth(authKeys, operation));
|
|
60
|
-
|
|
61
|
-
return fetchHar(har, self.userAgent).then(res => {
|
|
62
|
-
if (res.status >= 400 && res.status <= 599) {
|
|
63
|
-
throw res;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (config.parseResponse === false) return res;
|
|
67
|
-
|
|
68
|
-
return parseResponse(res);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function loadMethods(spec) {
|
|
74
|
-
const supportedVerbs = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
|
|
75
|
-
|
|
76
|
-
return supportedVerbs
|
|
77
|
-
.map(name => {
|
|
78
|
-
return {
|
|
79
|
-
[name]: ((method, path, ...args) => {
|
|
80
|
-
const operation = spec.operation(path, method);
|
|
81
|
-
return fetchOperation(spec, operation, ...args);
|
|
82
|
-
}).bind(null, name),
|
|
83
|
-
};
|
|
84
|
-
})
|
|
85
|
-
.reduce((prev, next) => Object.assign(prev, next));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function loadOperations(spec) {
|
|
89
|
-
return Sdk.getOperations(spec)
|
|
90
|
-
.filter(operation => operation.schema.operationId)
|
|
91
|
-
.reduce((prev, next) => {
|
|
92
|
-
return Object.assign(prev, {
|
|
93
|
-
[next.schema.operationId]: ((operation, ...args) => {
|
|
94
|
-
return fetchOperation(spec, operation, ...args);
|
|
95
|
-
}).bind(null, next),
|
|
96
|
-
});
|
|
97
|
-
}, {});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function loadFromCache() {
|
|
101
|
-
let cachedSpec;
|
|
102
|
-
if (isCached) {
|
|
103
|
-
cachedSpec = await cache.get();
|
|
104
|
-
} else {
|
|
105
|
-
cachedSpec = await cache.load();
|
|
106
|
-
isCached = true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const spec = new Oas(cachedSpec);
|
|
110
|
-
|
|
111
|
-
sdk = Object.assign(sdk, {
|
|
112
|
-
...loadMethods(spec),
|
|
113
|
-
...loadOperations(spec),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
isLoaded = true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const sdkProxy = {
|
|
120
|
-
get(target, method) {
|
|
121
|
-
// Since auth returns a self-proxy, we **do not** want it to fall through into the async function below as when
|
|
122
|
-
// that'll happen, instead of returning a self-proxy, it'll end up returning a Promise. When that happens,
|
|
123
|
-
// chaining `sdk.auth().operationId()` will fail.
|
|
124
|
-
if (['auth', 'config'].includes(method)) {
|
|
125
|
-
return function (...args) {
|
|
126
|
-
return target[method].apply(this, args);
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return async function (...args) {
|
|
131
|
-
if (!(method in target)) {
|
|
132
|
-
// If this method doesn't exist on the proxy (SDK), have we loaded the SDK? If we have, then this method
|
|
133
|
-
// isn't valid.
|
|
134
|
-
if (isLoaded) {
|
|
135
|
-
throw new Error(`Sorry, \`${method}\` does not appear to be a valid operation on this API.`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
await loadFromCache();
|
|
139
|
-
|
|
140
|
-
// If after loading the SDK and this method still doesn't exist, then it's not real!
|
|
141
|
-
if (!(method in sdk)) {
|
|
142
|
-
throw new Error(`Sorry, \`${method}\` does not appear to be a valid operation on this API.`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return sdk[method].apply(this, args);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return target[method].apply(this, args);
|
|
149
|
-
};
|
|
150
|
-
},
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
sdk = {
|
|
154
|
-
auth: (...values) => {
|
|
155
|
-
authKeys = values;
|
|
156
|
-
},
|
|
157
|
-
config: opts => {
|
|
158
|
-
// Downside to having `opts` be merged into the existing `config` is that there isn't a clean way to reset your
|
|
159
|
-
// current config to the default, so having `opts` assigned directly to the existing config should be okay.
|
|
160
|
-
config = opts;
|
|
161
|
-
return new Proxy(sdk, sdkProxy);
|
|
162
|
-
},
|
|
163
|
-
server: (url, variables = {}) => {
|
|
164
|
-
server = {
|
|
165
|
-
url,
|
|
166
|
-
variables,
|
|
167
|
-
};
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
return new Proxy(sdk, sdkProxy);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
module.exports = (uri, opts = {}) => {
|
|
176
|
-
return new Sdk(uri, opts).load();
|
|
177
|
-
};
|
package/src/lib/getSchema.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
utils: { findSchemaDefinition },
|
|
3
|
-
} = require('oas');
|
|
4
|
-
|
|
5
|
-
// Gets the schema of the first media type defined in the `content` of the path operation
|
|
6
|
-
// or returns the ref if there's no Request Body Object.
|
|
7
|
-
//
|
|
8
|
-
// If the ref looks like a `requestBodies` reference, then do a lookup for the actual schema
|
|
9
|
-
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields-8
|
|
10
|
-
module.exports = function getSchema(pathOperation, api) {
|
|
11
|
-
try {
|
|
12
|
-
if (pathOperation.requestBody.content) {
|
|
13
|
-
const type = Object.keys(pathOperation.requestBody.content)[0];
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
type,
|
|
17
|
-
schema: pathOperation.requestBody.content[type],
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (pathOperation.requestBody && pathOperation.requestBody.$ref.match(/^#\/components\/requestBodies\/.*$/)) {
|
|
22
|
-
return getSchema({
|
|
23
|
-
requestBody: findSchemaDefinition(pathOperation.requestBody.$ref, api),
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
type: 'application/json',
|
|
29
|
-
schema: pathOperation.requestBody,
|
|
30
|
-
};
|
|
31
|
-
} catch (e) {} // eslint-disable-line no-empty
|
|
32
|
-
|
|
33
|
-
return undefined;
|
|
34
|
-
};
|
package/src/lib/index.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const parseResponse = require('./parseResponse');
|
|
2
|
-
const prepareAuth = require('./prepareAuth');
|
|
3
|
-
const prepareParams = require('./prepareParams');
|
|
4
|
-
const prepareServer = require('./prepareServer');
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
parseResponse,
|
|
8
|
-
prepareAuth,
|
|
9
|
-
prepareParams,
|
|
10
|
-
prepareServer,
|
|
11
|
-
};
|
package/src/lib/prepareAuth.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-underscore-dangle */
|
|
2
|
-
/**
|
|
3
|
-
* @todo Needs work for supporting multiple different kinds of auth at the same time. for example if
|
|
4
|
-
* an operation uses OAuth and HTTP bearer, how can we guarantee that the OAuth bearer is used with
|
|
5
|
-
* OAuth?
|
|
6
|
-
*
|
|
7
|
-
* @param {Array} authKeys
|
|
8
|
-
* @param {Operation} operation
|
|
9
|
-
*/
|
|
10
|
-
module.exports = (authKey, operation) => {
|
|
11
|
-
if (authKey.length === 0) {
|
|
12
|
-
return {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const prepared = {};
|
|
16
|
-
const security = operation.prepareSecurity();
|
|
17
|
-
const securitySchemes = Object.keys(security);
|
|
18
|
-
|
|
19
|
-
if (securitySchemes.length === 0) {
|
|
20
|
-
// If there's no auth configured on this operation, don't prepare anything (even if it was supplied by the user).
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const securityType = securitySchemes[0];
|
|
25
|
-
const schemes = security[securityType];
|
|
26
|
-
if (schemes.length > 1) {
|
|
27
|
-
throw new Error("Sorry, this API currently requires multiple forms of authentication which we don't yet support.");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const scheme = schemes[0];
|
|
31
|
-
if (scheme.type === 'http') {
|
|
32
|
-
if (scheme.scheme === 'basic') {
|
|
33
|
-
prepared[scheme._key] = {
|
|
34
|
-
user: authKey[0],
|
|
35
|
-
pass: authKey.length === 2 ? authKey[1] : '',
|
|
36
|
-
};
|
|
37
|
-
} else if (scheme.scheme === 'bearer') {
|
|
38
|
-
if (authKey.length > 1) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
'Multiple auth tokens were supplied for the auth on this endpoint, but only a single token is needed.'
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
prepared[scheme._key] = authKey[0];
|
|
45
|
-
}
|
|
46
|
-
} else if (scheme.type === 'oauth2') {
|
|
47
|
-
if (authKey.length > 1) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
'Multiple auth tokens were supplied for the auth on this endpoint, but only a single token is needed.'
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
prepared[scheme._key] = authKey[0];
|
|
54
|
-
} else if (scheme.type === 'apiKey') {
|
|
55
|
-
if (authKey.length > 1) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
'Multiple auth keys were supplied for the auth on this endpoint, but only a single key is needed.'
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (scheme.in === 'query' || scheme.in === 'header') {
|
|
62
|
-
prepared[scheme._key] = authKey[0];
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
throw new Error(`Sorry, this API currently supports a scheme, ${scheme.type}, that we don't yet support.`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return prepared;
|
|
69
|
-
};
|
package/src/lib/prepareParams.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const stream = require('stream');
|
|
4
|
-
const mimer = require('mimer');
|
|
5
|
-
const getStream = require('get-stream');
|
|
6
|
-
const datauri = require('datauri');
|
|
7
|
-
const getSchema = require('./getSchema');
|
|
8
|
-
|
|
9
|
-
function digestParameters(parameters) {
|
|
10
|
-
return parameters.reduce((prev, param) => {
|
|
11
|
-
if ('$ref' in param || 'allOf' in param || 'anyOf' in param || 'oneOf' in param) {
|
|
12
|
-
throw new Error(`The OpenAPI document for this operation wasn't dereferenced before processing.`);
|
|
13
|
-
} else if (param.name in prev) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
`The operation you are using has the same parameter, ${param.name}, spread across multiple entry points. We unfortunately can't handle this right now.`
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return Object.assign(prev, { [param.name]: param });
|
|
20
|
-
}, {});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_isempty
|
|
24
|
-
function isEmpty(obj) {
|
|
25
|
-
return [Object, Array].includes((obj || {}).constructor) && !Object.entries(obj || {}).length;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
module.exports = async (operation, body, metadata) => {
|
|
29
|
-
// If no data was supplied, just return immediately.
|
|
30
|
-
if (isEmpty(body) && isEmpty(metadata)) {
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const params = {};
|
|
35
|
-
let shouldDigestParams = false;
|
|
36
|
-
|
|
37
|
-
if (Array.isArray(body)) {
|
|
38
|
-
// If the body param is an array, then it's absolutely a body and not something we need to do analysis against.
|
|
39
|
-
params.body = body;
|
|
40
|
-
|
|
41
|
-
if (typeof metadata !== 'undefined') {
|
|
42
|
-
shouldDigestParams = true;
|
|
43
|
-
}
|
|
44
|
-
} else if (typeof metadata === 'undefined') {
|
|
45
|
-
// No metadata was explicitly defined so we need to analyze the body to determine if it should actually be treated
|
|
46
|
-
// as metadata.
|
|
47
|
-
shouldDigestParams = true;
|
|
48
|
-
} else {
|
|
49
|
-
// Body and metadata were both supplied.
|
|
50
|
-
params.body = body;
|
|
51
|
-
shouldDigestParams = true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let digested = {};
|
|
55
|
-
let hasDigestedParams = false;
|
|
56
|
-
if (shouldDigestParams) {
|
|
57
|
-
digested = digestParameters(operation.getParameters());
|
|
58
|
-
hasDigestedParams = Object.keys(digested).length;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// No metadata was explicitly defined so we need to analyze the supplied, and we haven't already set a body then we
|
|
62
|
-
// need to analyze the supplied body to see if it should actually be metadata. If not, then we can just treat it as a
|
|
63
|
-
// body and pass it along.
|
|
64
|
-
if (!('body' in params) && typeof metadata === 'undefined') {
|
|
65
|
-
if (!hasDigestedParams) {
|
|
66
|
-
// No parameters were able to be digested, so we just have to assume that what the user supplied was for a body.
|
|
67
|
-
// This might lead to unwanted false positives if an OAS isn't accurate, but short of throwing an error there
|
|
68
|
-
// isn't anything we can really do about it.
|
|
69
|
-
params.body = body;
|
|
70
|
-
} else {
|
|
71
|
-
const intersection = Object.keys(body).filter(value => Object.keys(digested).includes(value)).length;
|
|
72
|
-
if (intersection && intersection / Object.keys(body).length > 0.25) {
|
|
73
|
-
// If more than 25% of the body intersects with the parameters that we've got on hand, then we should treat it
|
|
74
|
-
// as a metadata object and organize into parameters.
|
|
75
|
-
// eslint-disable-next-line no-param-reassign
|
|
76
|
-
metadata = body;
|
|
77
|
-
} else {
|
|
78
|
-
// For all other cases, we should just treat the supplied body as a body.
|
|
79
|
-
params.body = body;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// @todo support content types like `image/png` where the request body is the binary
|
|
85
|
-
|
|
86
|
-
// If the operation is `multipart/form-data`, or one of our recognized variants, we need to look at the incoming
|
|
87
|
-
// body payload to see if anything in there is either a file path or a file stream so we can translate those into a
|
|
88
|
-
// data URL for `@readme/oas-to-har` to make a request.
|
|
89
|
-
if ('body' in params && operation.isMultipart()) {
|
|
90
|
-
let requestBody = getSchema(operation.schema, operation.api);
|
|
91
|
-
if (requestBody) {
|
|
92
|
-
requestBody = requestBody.schema;
|
|
93
|
-
} else {
|
|
94
|
-
requestBody = { schema: {} };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const bodyKeys = Object.keys(params.body);
|
|
98
|
-
|
|
99
|
-
// Loop through the schema to look for `binary` properties so we know what we need to convert.
|
|
100
|
-
const conversions = [];
|
|
101
|
-
Object.keys(requestBody.schema.properties)
|
|
102
|
-
.filter(key => requestBody.schema.properties[key].format === 'binary')
|
|
103
|
-
.filter(x => bodyKeys.includes(x))
|
|
104
|
-
.forEach(async prop => {
|
|
105
|
-
let file = params.body[prop];
|
|
106
|
-
if (typeof file === 'string') {
|
|
107
|
-
// In order to support relative pathed files, we need to attempt to resolve them. Thankfully `path.resolve()`
|
|
108
|
-
// doesn't munge absolute paths.
|
|
109
|
-
file = path.resolve(file);
|
|
110
|
-
if (fs.existsSync(file)) {
|
|
111
|
-
conversions.push(
|
|
112
|
-
new Promise(resolve => {
|
|
113
|
-
resolve(datauri(file));
|
|
114
|
-
}).then(dataurl => {
|
|
115
|
-
// Doing this manually for now until when/if https://github.com/data-uri/datauri/pull/29 is accepted.
|
|
116
|
-
params.body[prop] = dataurl.replace(
|
|
117
|
-
';base64',
|
|
118
|
-
`;name=${encodeURIComponent(path.basename(file))};base64`
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
return Promise.resolve(true);
|
|
122
|
-
})
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
} else if (file instanceof stream.Readable) {
|
|
126
|
-
conversions.push(
|
|
127
|
-
new Promise(resolve => {
|
|
128
|
-
resolve(getStream.buffer(file));
|
|
129
|
-
}).then(buffer => {
|
|
130
|
-
// This logic was taken from the `datauri` package, and ideally it should be able to accept the content
|
|
131
|
-
// of a file, or a file stream, but I'll PR that later to that package.
|
|
132
|
-
// @todo
|
|
133
|
-
const base64 = buffer.toString('base64');
|
|
134
|
-
const mimeType = mimer(file.path);
|
|
135
|
-
const filepath = path.basename(file.path);
|
|
136
|
-
|
|
137
|
-
params.body[prop] = `data:${mimeType};name=${encodeURIComponent(filepath)};base64,${base64 || ''}`;
|
|
138
|
-
|
|
139
|
-
return Promise.resolve(true);
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
await Promise.all(conversions);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// @todo add in a debug mode that would run jsonschema validation against request bodies and parameters and throw back errors if what's supplied isn't up to spec.
|
|
149
|
-
|
|
150
|
-
// Only spend time trying to organize metadata into parameters if we were able to digest parameters out of the
|
|
151
|
-
// operation schema. If we couldn't digest anything, but metadata was supplied then we wouldn't know where to place
|
|
152
|
-
// the metadata!
|
|
153
|
-
if (hasDigestedParams) {
|
|
154
|
-
params.header = {};
|
|
155
|
-
params.path = {};
|
|
156
|
-
params.query = {};
|
|
157
|
-
|
|
158
|
-
if (typeof metadata === 'object' && !isEmpty(metadata)) {
|
|
159
|
-
const metadataKeys = Object.keys(metadata);
|
|
160
|
-
if (metadataKeys.length) {
|
|
161
|
-
metadataKeys.forEach(param => {
|
|
162
|
-
if (!(param in digested)) {
|
|
163
|
-
// This param isn't documented in the OAS, so we can't know where to put it!
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (digested[param].in === 'path') {
|
|
168
|
-
params.path[param] = metadata[param];
|
|
169
|
-
} else if (digested[param].in === 'query') {
|
|
170
|
-
params.query[param] = metadata[param];
|
|
171
|
-
} else if (digested[param].in === 'header') {
|
|
172
|
-
params.header[param] = metadata[param];
|
|
173
|
-
} else if (digested[param].in === 'cookie') {
|
|
174
|
-
// @todo add support cookie params here and also in @readme/oas-to-har
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Form data should be placed inside `formData` instead of `body` for it to properly get picked up.
|
|
182
|
-
if (operation.isFormUrlEncoded()) {
|
|
183
|
-
params.formData = body;
|
|
184
|
-
delete params.body;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// @todo add required params with defaults if they aren't supplied
|
|
188
|
-
// @todo in debug mode, if a path param is missing (and required -- they always are), and no defaults are present, we should throw an error
|
|
189
|
-
|
|
190
|
-
// Clean up any empty items.
|
|
191
|
-
['body', 'formData', 'header', 'path', 'query'].forEach(type => {
|
|
192
|
-
if (type in params && Object.keys(params[type]).length === 0) {
|
|
193
|
-
delete params[type];
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return params;
|
|
198
|
-
};
|