api 4.2.0 → 4.4.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/README.md +6 -3
- package/package.json +5 -5
- package/src/index.js +2 -3
- package/src/lib/getSchema.js +34 -0
- package/src/lib/parseResponse.js +8 -10
- package/src/lib/prepareAuth.js +35 -38
- package/src/lib/prepareParams.js +1 -3
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Using `api` is as simple as supplying it an OpenAPI and using the SDK as you wou
|
|
|
25
25
|
```js
|
|
26
26
|
const sdk = require('api')('https://raw.githubusercontent.com/readmeio/oas/master/packages/examples/3.0/json/petstore.json');
|
|
27
27
|
|
|
28
|
-
sdk.listPets().then(res =>
|
|
28
|
+
sdk.listPets().then(res => {
|
|
29
29
|
console.log(`My pets name is ${res[0].name}!`);
|
|
30
30
|
});
|
|
31
31
|
```
|
|
@@ -33,10 +33,11 @@ sdk.listPets().then(res => res.json()).then(res => {
|
|
|
33
33
|
The OpenAPI definition is automatically downloaded, cached, and transformed into a chainable [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) Promise that you can use to make API requests.
|
|
34
34
|
|
|
35
35
|
### Authentication
|
|
36
|
-
`api` supports API authentication through an `.auth()` method
|
|
36
|
+
`api` supports API authentication through an `.auth()` method:
|
|
37
37
|
|
|
38
38
|
```js
|
|
39
|
-
sdk.auth('myApiToken')
|
|
39
|
+
sdk.auth('myApiToken');
|
|
40
|
+
sdk.listPets().then(...);
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
With the exception of OpenID, it supports all forms of authentication supported by the OpenAPI specification! Just give `.auth()` your credentials and it'll figure out how to use it according to the API you're using.
|
|
@@ -47,6 +48,8 @@ For example:
|
|
|
47
48
|
* Bearer tokens (HTTP or OAuth 2): `sdk.auth('myBearerToken')`
|
|
48
49
|
* API Keys: `sdk.auth('myApiKey')`
|
|
49
50
|
|
|
51
|
+
> ℹ️ Note that `sdk.auth()` is not chainable.
|
|
52
|
+
|
|
50
53
|
### Parameters and Payloads
|
|
51
54
|
When supplying parameters and/or request body payloads to an API request, you don't need to explicitly define what goes where since the API definition contains all that information. All you need to do is supply either one or two objects:
|
|
52
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Generate an SDK from an OpenAPI definition",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"node": "^12 || ^14 || ^16"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@readme/oas-to-har": "^
|
|
27
|
-
"@readme/openapi-parser": "^2.
|
|
26
|
+
"@readme/oas-to-har": "^16.1.0",
|
|
27
|
+
"@readme/openapi-parser": "^2.1.0",
|
|
28
28
|
"datauri": "^4.1.0",
|
|
29
29
|
"fetch-har": "^5.0.5",
|
|
30
30
|
"find-cache-dir": "^3.3.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"make-dir": "^3.1.0",
|
|
35
35
|
"mimer": "^2.0.2",
|
|
36
36
|
"node-fetch": "^2.6.0",
|
|
37
|
-
"oas": "^
|
|
37
|
+
"oas": "^18.1.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@readme/eslint-config": "^8.0.2",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"__tests__/__fixtures__/"
|
|
52
52
|
]
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "dab29250c2aea8ff2148aa35d50f9fc11cf69647"
|
|
55
55
|
}
|
package/src/index.js
CHANGED
|
@@ -29,7 +29,7 @@ class Sdk {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
load() {
|
|
32
|
-
|
|
32
|
+
let authKeys = [];
|
|
33
33
|
const cache = new Cache(this.uri);
|
|
34
34
|
const self = this;
|
|
35
35
|
let config = { parseResponse: true };
|
|
@@ -150,8 +150,7 @@ class Sdk {
|
|
|
150
150
|
|
|
151
151
|
sdk = {
|
|
152
152
|
auth: (...values) => {
|
|
153
|
-
authKeys
|
|
154
|
-
return new Proxy(sdk, sdkProxy);
|
|
153
|
+
authKeys = values;
|
|
155
154
|
},
|
|
156
155
|
config: opts => {
|
|
157
156
|
// Downside to having `opts` be merged into the existing `config` is that there isn't a clean way to reset your
|
|
@@ -0,0 +1,34 @@
|
|
|
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/parseResponse.js
CHANGED
|
@@ -6,18 +6,16 @@ const {
|
|
|
6
6
|
|
|
7
7
|
module.exports = async function getResponseBody(response) {
|
|
8
8
|
const contentType = response.headers.get('Content-Type');
|
|
9
|
-
const
|
|
9
|
+
const isJSON = contentType && (matchesMimeType.json(contentType) || matchesMimeType.wildcard(contentType));
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
// we cannot parse it as JSON later, then we can
|
|
13
|
-
// re-read again as plain text
|
|
14
|
-
const clonedResponse = response.clone();
|
|
15
|
-
let responseBody;
|
|
11
|
+
const responseBody = await response.text();
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
if (isJSON) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(responseBody);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
// If our JSON parsing failed then we can just return plaintext instead.
|
|
18
|
+
}
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
return responseBody;
|
package/src/lib/prepareAuth.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* @param {Array} authKeys
|
|
8
8
|
* @param {Operation} operation
|
|
9
9
|
*/
|
|
10
|
-
module.exports = (
|
|
11
|
-
if (
|
|
10
|
+
module.exports = (authKey, operation) => {
|
|
11
|
+
if (authKey.length === 0) {
|
|
12
12
|
return {};
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -21,31 +21,20 @@ module.exports = (authKeys, operation) => {
|
|
|
21
21
|
return {};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const scheme = schemes[0];
|
|
33
|
-
if (scheme.type === 'http') {
|
|
34
|
-
if (scheme.scheme === 'basic') {
|
|
35
|
-
prepared[scheme._key] = {
|
|
36
|
-
user: authKey[0],
|
|
37
|
-
pass: authKey.length === 2 ? authKey[1] : '',
|
|
38
|
-
};
|
|
39
|
-
} else if (scheme.scheme === 'bearer') {
|
|
40
|
-
if (authKey.length > 1) {
|
|
41
|
-
throw new Error(
|
|
42
|
-
'Multiple auth tokens were supplied for the auth on this endpoint, but only a single token is needed.'
|
|
43
|
-
);
|
|
44
|
-
}
|
|
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
|
+
}
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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') {
|
|
49
38
|
if (authKey.length > 1) {
|
|
50
39
|
throw new Error(
|
|
51
40
|
'Multiple auth tokens were supplied for the auth on this endpoint, but only a single token is needed.'
|
|
@@ -53,20 +42,28 @@ module.exports = (authKeys, operation) => {
|
|
|
53
42
|
}
|
|
54
43
|
|
|
55
44
|
prepared[scheme._key] = authKey[0];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
}
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
+
);
|
|
68
59
|
}
|
|
69
|
-
|
|
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
|
+
}
|
|
70
67
|
|
|
71
68
|
return prepared;
|
|
72
69
|
};
|
package/src/lib/prepareParams.js
CHANGED
|
@@ -4,9 +4,7 @@ const stream = require('stream');
|
|
|
4
4
|
const mimer = require('mimer');
|
|
5
5
|
const getStream = require('get-stream');
|
|
6
6
|
const datauri = require('datauri');
|
|
7
|
-
const
|
|
8
|
-
utils: { getSchema },
|
|
9
|
-
} = require('oas');
|
|
7
|
+
const getSchema = require('./getSchema');
|
|
10
8
|
|
|
11
9
|
function digestParameters(parameters) {
|
|
12
10
|
return parameters.reduce((prev, param) => {
|