Skip to content

Commit 431a7db

Browse files
authored
fix(openapi): error handling for incorrect project and version flags (#411)
* test: fix version creation flow in nock It doesn't make sense that the API would return v1.0.1 if that's the version the user is trying to create! So this fixes that. The test still passes ¯\_(ツ)_/¯ * fix: properly bubble up errors finding versions also add a couple tests * refactor: get rid of unnecessary catch statement This is being caught by the caller function, so this isn't necessary. Also the tests yield the same result. * refactor: another place with unnecessary catch statements Tests still pass, so I think we're good here.
1 parent 8b9ad4b commit 431a7db

File tree

3 files changed

+64
-18
lines changed

3 files changed

+64
-18
lines changed

__tests__/cmds/openapi.test.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,36 @@ describe('rdme openapi', () => {
190190
});
191191

192192
describe('versioning', () => {
193-
it.todo('should return a 404 if version flag not found');
193+
it('should error if version flag sent to API returns a 404', async () => {
194+
const invalidVersion = 'v1000';
195+
196+
const errorObject = {
197+
error: 'VERSION_NOTFOUND',
198+
message: `The version you specified (${invalidVersion}) doesn't match any of the existing versions (1.0) in ReadMe.`,
199+
suggestion:
200+
'You can pass the version in via the `x-readme-version` header. If you want to create a new version, do so in the Versions section inside ReadMe. Note that the version in the URL is our API version, not the version of your docs.',
201+
docs: 'https://docs.readme.com/logs/xx-xx-xx',
202+
help: "If you need help, email support@readme.io and include the following link to your API log: 'https://docs.readme.com/logs/xx-xx-xx'.",
203+
poem: [
204+
'We looked high and low,',
205+
'Searched up, down and around.',
206+
"You'll have to give it another go,",
207+
`Because version ${invalidVersion}'s not found!`,
208+
],
209+
};
210+
211+
const mock = nock(config.host).get(`/api/v1/version/${invalidVersion}`).reply(404, errorObject);
212+
213+
await expect(
214+
openapi.run({
215+
spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json'),
216+
key,
217+
version: invalidVersion,
218+
})
219+
).rejects.toStrictEqual(new APIError(errorObject));
220+
221+
return mock.done();
222+
});
194223

195224
it('should request a version list if version is not found', async () => {
196225
promptHandler.generatePrompts.mockResolvedValue({
@@ -201,10 +230,10 @@ describe('rdme openapi', () => {
201230
const mock = nock(config.host)
202231
.get('/api/v1/version')
203232
.basicAuth({ user: key })
204-
.reply(200, [{ version: '1.0.1' }])
233+
.reply(200, [{ version: '1.0.0' }])
205234
.post('/api/v1/version')
206235
.basicAuth({ user: key })
207-
.reply(200, { from: '1.0.1', version: '1.0.1' })
236+
.reply(200, { from: '1.0.0', version: '1.0.1' })
208237
.get('/api/v1/api-specification')
209238
.basicAuth({ user: key })
210239
.reply(200, [])
@@ -256,6 +285,31 @@ describe('rdme openapi', () => {
256285
).rejects.toThrow('No project API key provided. Please use `--key`.');
257286
});
258287

288+
it('should error if invalid API key is sent and version list does not load', async () => {
289+
const errorObject = {
290+
error: 'APIKEY_NOTFOUND',
291+
message: "We couldn't find your API key.",
292+
suggestion:
293+
"The API key you passed in (API_KEY) doesn't match any keys we have in our system. API keys must be passed in as the username part of basic auth. You can get your API key in Configuration > API Key, or in the docs.",
294+
docs: 'https://docs.readme.com/logs/xx-xx-xx',
295+
help: "If you need help, email support@readme.io and include the following link to your API log: 'https://docs.readme.com/logs/xx-xx-xx'.",
296+
poem: [
297+
'The ancient gatekeeper declares:',
298+
"'To pass, reveal your API key.'",
299+
"'API_KEY', you start to ramble",
300+
'Oops, you remembered it poorly!',
301+
],
302+
};
303+
304+
const mock = nock(config.host).get('/api/v1/version').reply(401, errorObject);
305+
306+
await expect(
307+
openapi.run({ key, spec: require.resolve('@readme/oas-examples/3.1/json/petstore.json') })
308+
).rejects.toStrictEqual(new APIError(errorObject));
309+
310+
return mock.done();
311+
});
312+
259313
it('should error if no file was provided or able to be discovered', async () => {
260314
const mock = nock(config.host)
261315
.get(`/api/v1/version/${version}`)

src/cmds/openapi.js

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,10 @@ exports.run = async function (opts) {
118118

119119
let bundledSpec;
120120
const oas = new OASNormalize(specPath, { colorizeErrors: true, enablePaths: true });
121-
await oas.validate(false).catch(err => {
122-
return Promise.reject(err);
121+
await oas.validate(false);
122+
await oas.bundle().then(res => {
123+
bundledSpec = JSON.stringify(res);
123124
});
124-
await oas
125-
.bundle()
126-
.then(res => {
127-
bundledSpec = JSON.stringify(res);
128-
})
129-
.catch(err => {
130-
return Promise.reject(err);
131-
});
132125

133126
// Create a temporary file to write the bundled spec to,
134127
// which we will then stream into the form data body
@@ -204,9 +197,7 @@ exports.run = async function (opts) {
204197
}
205198

206199
if (!id) {
207-
selectedVersion = await getProjectVersion(version, key, true).catch(e => {
208-
return Promise.reject(e);
209-
});
200+
selectedVersion = await getProjectVersion(version, key, true);
210201
}
211202

212203
if (spec) {

src/lib/versionSelect.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { cleanHeaders } = require('./cleanHeaders');
44
const fetch = require('node-fetch');
55
const config = require('config');
66
const APIError = require('./apiError');
7+
const { handleRes } = require('./handleRes');
78

89
async function getProjectVersion(versionFlag, key, allowNewVersion) {
910
try {
@@ -12,14 +13,14 @@ async function getProjectVersion(versionFlag, key, allowNewVersion) {
1213
method: 'get',
1314
headers: cleanHeaders(key),
1415
})
15-
.then(res => res.json())
16+
.then(res => handleRes(res))
1617
.then(res => res.version);
1718
}
1819

1920
const versionList = await fetch(`${config.host}/api/v1/version`, {
2021
method: 'get',
2122
headers: cleanHeaders(key),
22-
}).then(res => res.json());
23+
}).then(res => handleRes(res));
2324

2425
if (allowNewVersion) {
2526
const { option, versionSelection, newVersion } = await prompt(promptOpts.generatePrompts(versionList));

0 commit comments

Comments
 (0)