Skip to content

Commit ab132ea

Browse files
authored
Cache OpenAPI using next "use cache" for v2 (#2887)
1 parent 14504e4 commit ab132ea

File tree

4 files changed

+69
-29
lines changed

4 files changed

+69
-29
lines changed

packages/gitbook/e2e/util.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ export function runTestCases(testCases: TestsCase[]) {
154154
}))
155155
);
156156
}
157+
158+
// Disable the Vercel toolbar
159+
await page.setExtraHTTPHeaders({
160+
'x-vercel-skip-toolbar': '1',
161+
});
162+
157163
await page.goto(url);
158164
if (testEntry.run) {
159165
await testEntry.run(page);

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

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { GitBookAnyContext } from '@v2/lib/context';
66
import { type CacheFunctionOptions, cache, noCacheFetchOptions } from '@/lib/cache';
77

88
import { resolveContentRef } from '../references';
9+
import { isV2 } from '../v2';
910
import { enrichFilesystem } from './enrich';
1011

1112
const weakmap = new WeakMap<DocumentBlockOpenAPI, ResolveOpenAPIBlockResult>();
@@ -65,32 +66,18 @@ async function baseResolveOpenAPIBlock(args: ResolveOpenAPIBlockArgs): ResolveOp
6566
}
6667
}
6768

68-
const fetchFilesystem = cache({
69-
name: 'openapi.fetch.v6',
70-
get: async (url: string, options: CacheFunctionOptions) => {
71-
// Wrap the raw string to prevent invalid URLs from being passed to fetch.
72-
// This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch:
73-
// https://github.com/cloudflare/workerd/issues/1957
74-
const response = await fetch(new URL(url), {
75-
...noCacheFetchOptions,
76-
signal: options.signal,
77-
});
69+
function fetchFilesystem(url: string) {
70+
if (isV2()) {
71+
return fetchFilesystemV2(url);
72+
}
7873

79-
if (!response.ok) {
80-
throw new Error(
81-
`Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`
82-
);
83-
}
74+
return fetchFilesystemV1(url);
75+
}
8476

85-
const text = await response.text();
86-
const filesystem = await parseOpenAPI({
87-
value: text,
88-
rootURL: url,
89-
// If we fetch the OpenAPI specification
90-
// it's the legacy system, it means the spec can be trusted here.
91-
trust: true,
92-
});
93-
const richFilesystem = await enrichFilesystem(filesystem);
77+
const fetchFilesystemV1 = cache({
78+
name: 'openapi.fetch.v6',
79+
get: async (url: string, options: CacheFunctionOptions) => {
80+
const richFilesystem = await fetchFilesystemUncached(url, options);
9481
return {
9582
// Cache for 4 hours
9683
ttl: 24 * 60 * 60,
@@ -100,3 +87,44 @@ const fetchFilesystem = cache({
10087
};
10188
},
10289
});
90+
91+
async function fetchFilesystemV2(url: string) {
92+
'use cache';
93+
94+
// TODO: add cache lifetime once we can use next.js 15 code here
95+
96+
const response = await fetchFilesystemUncached(url);
97+
98+
return response;
99+
}
100+
101+
async function fetchFilesystemUncached(
102+
url: string,
103+
options?: {
104+
signal?: AbortSignal;
105+
}
106+
) {
107+
// Wrap the raw string to prevent invalid URLs from being passed to fetch.
108+
// This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch:
109+
// https://github.com/cloudflare/workerd/issues/1957
110+
const response = await fetch(new URL(url), {
111+
...noCacheFetchOptions,
112+
signal: options?.signal,
113+
});
114+
115+
if (!response.ok) {
116+
throw new Error(`Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`);
117+
}
118+
119+
const text = await response.text();
120+
const filesystem = await parseOpenAPI({
121+
value: text,
122+
rootURL: url,
123+
// If we fetch the OpenAPI specification
124+
// it's the legacy system, it means the spec can be trusted here.
125+
trust: true,
126+
});
127+
const richFilesystem = await enrichFilesystem(filesystem);
128+
129+
return richFilesystem;
130+
}

packages/gitbook/src/lib/v2.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
/**
2+
* Check if the code is running in v2.
3+
*/
4+
export function isV2() {
5+
return process.env.GITBOOK_V2 === 'true';
6+
}
7+
18
/**
29
* Assert that the code is not running in v2.
310
*/
411
export function assertIsNotV2() {
5-
if (process.env.GITBOOK_V2 === 'true') {
12+
if (isV2()) {
613
throw new Error('This code is not available in V2');
714
}
815
}

packages/react-openapi/src/OpenAPICodeSample.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { generateMediaTypeExample, generateSchemaExample } from './generateSchem
55
import { stringifyOpenAPI } from './stringifyOpenAPI';
66
import type { OpenAPIContextProps, OpenAPIOperationData } from './types';
77
import { getDefaultServerURL } from './util/server';
8-
import { createStateKey } from './utils';
9-
import { checkIsReference } from './utils';
8+
import { checkIsReference, createStateKey } from './utils';
109

1110
/**
1211
* Display code samples to execute the operation.
@@ -95,8 +94,8 @@ export function OpenAPICodeSample(props: {
9594
typeof sample.lang === 'string'
9695
);
9796
})
98-
.map((sample) => ({
99-
key: `redocly-${sample.lang}`,
97+
.map((sample, index) => ({
98+
key: `redocly-${sample.lang}-${index}`,
10099
label: sample.label,
101100
body: context.renderCodeBlock({
102101
code: sample.source,

0 commit comments

Comments
 (0)