Skip to content

Commit a385525

Browse files
conico974Nicolas Dorseuil
andauthored
Gracefully handle OpenAPI fetch errors (#3455)
Co-authored-by: Nicolas Dorseuil <nicolas@gitbook.io>
1 parent 9169c2f commit a385525

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

packages/gitbook/src/lib/openapi/fetch.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import { OpenAPIParseError, parseOpenAPI } from '@gitbook/openapi-parser';
1+
import {
2+
type Filesystem,
3+
OpenAPIParseError,
4+
type OpenAPIParseErrorCode,
5+
parseOpenAPI,
6+
} from '@gitbook/openapi-parser';
27

3-
import { noCacheFetchOptions } from '@/lib/data';
8+
import { DataFetcherError, noCacheFetchOptions } from '@/lib/data';
49
import { resolveContentRef } from '@/lib/references';
510
import { unstable_cacheLife as cacheLife } from 'next/cache';
611
import { assert } from 'ts-essentials';
@@ -48,18 +53,35 @@ export async function fetchOpenAPIFilesystem(
4853
};
4954
}
5055

51-
const fetchFilesystem = async (url: string) => {
56+
const fetchFilesystem = async (
57+
url: string
58+
): Promise<
59+
| Filesystem
60+
| {
61+
error: {
62+
code: OpenAPIParseErrorCode;
63+
message: string;
64+
};
65+
}
66+
> => {
5267
'use cache';
5368
try {
5469
return await fetchFilesystemUncached(url);
5570
} catch (error) {
71+
// To avoid hammering the file with requests, we cache the error for around a minute.
72+
cacheLife('minutes');
5673
// Throwing an error inside a "use cache" function obfuscates the error,
5774
// so we need to handle it here and recreates the error outside the cache function.
5875
if (error instanceof OpenAPIParseError) {
59-
cacheLife('seconds');
6076
return { error: { code: error.code, message: error.message } };
6177
}
62-
throw error;
78+
if (error instanceof DataFetcherError) {
79+
return { error: { code: 'invalid' as const, message: 'Failed to fetch OpenAPI file' } };
80+
}
81+
// If the error is not an OpenAPIParseError or DataFetcherError,
82+
// we assume it's an unknown error and return a generic error.
83+
console.error('Unknown error while fetching OpenAPI file:', error);
84+
return { error: { code: 'invalid' as const, message: 'Unknown error' } };
6385
}
6486
};
6587

@@ -78,7 +100,7 @@ async function fetchFilesystemUncached(
78100
});
79101

80102
if (!response.ok) {
81-
throw new Error(`Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`);
103+
throw new DataFetcherError('Failed to fetch OpenAPI file', response.status);
82104
}
83105

84106
const text = await response.text();

packages/openapi-parser/src/error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ErrorObject } from '@scalar/openapi-parser';
22

3-
type OpenAPIParseErrorCode =
3+
export type OpenAPIParseErrorCode =
44
| 'invalid'
55
| 'parse-v2-in-v3'
66
| 'v2-conversion'

0 commit comments

Comments
 (0)