Skip to content

Commit 2c44ef3

Browse files
Validate API response against Zod schema
Signed-off-by: Andy Jakubowski <[email protected]>
1 parent 83879a8 commit 2c44ef3

File tree

2 files changed

+21
-19
lines changed

2 files changed

+21
-19
lines changed

src/deepnote-content-provider.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
import { Contents, RestContentProvider } from '@jupyterlab/services';
22
import { transformDeepnoteYamlToNotebookContent } from './transform-deepnote-yaml-to-notebook-content';
33
import { requestAPI } from './handler';
4+
import { z } from 'zod';
45

56
export const deepnoteContentProviderName = 'deepnote-content-provider';
7+
8+
const deepnoteFileResponseSchema = z.object({
9+
deepnoteFileModel: z.object({
10+
name: z.string(),
11+
path: z.string(),
12+
created: z.string(),
13+
last_modified: z.string(),
14+
content: z.string(),
15+
mimetype: z.string().optional()
16+
})
17+
});
18+
619
export class DeepnoteContentProvider extends RestContentProvider {
720
async get(
821
localPath: string,
@@ -17,24 +30,13 @@ export class DeepnoteContentProvider extends RestContentProvider {
1730
}
1831

1932
// Call custom API route to fetch the Deepnote file content
20-
let data: any;
21-
22-
try {
23-
data = await requestAPI<any>(
24-
`file?path=${encodeURIComponent(localPath)}`
25-
);
26-
} catch (error) {
27-
console.error(`Failed to fetch Deepnote file: ${localPath}`, error);
28-
throw new Error(`Failed to fetch .deepnote file: ${error}`);
33+
const data = await requestAPI(`file?path=${encodeURIComponent(localPath)}`);
34+
const parsed = deepnoteFileResponseSchema.safeParse(data);
35+
if (!parsed.success) {
36+
console.error('Invalid API response shape', parsed.error);
37+
throw new Error('Invalid API response shape');
2938
}
30-
31-
if (!data.deepnoteFileModel) {
32-
throw new Error(
33-
`Invalid API response: missing deepnoteFileModel for ${localPath}`
34-
);
35-
}
36-
37-
const modelData = data.deepnoteFileModel;
39+
const modelData = parsed.data.deepnoteFileModel;
3840

3941
// Transform the Deepnote YAML to Jupyter notebook content
4042
const notebookContent = await transformDeepnoteYamlToNotebookContent(

src/handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { ServerConnection } from '@jupyterlab/services';
99
* @param init Initial values for the request
1010
* @returns The response body interpreted as JSON
1111
*/
12-
export async function requestAPI<T>(
12+
export async function requestAPI(
1313
endPoint = '',
1414
init: RequestInit = {}
15-
): Promise<T> {
15+
): Promise<unknown> {
1616
// Make request to Jupyter API
1717
const settings = ServerConnection.makeSettings();
1818
const requestUrl = URLExt.join(

0 commit comments

Comments
 (0)