Skip to content

Commit 4e63e18

Browse files
committed
fix(errors): add custom errors
Updates the UploadController to use custom errors. The custom errors are defined in a uploads lib directory and handles all cases found in the controller.
1 parent 73c2e4b commit 4e63e18

File tree

2 files changed

+94
-30
lines changed

2 files changed

+94
-30
lines changed

src/controllers/UploadController.ts

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import {
99
} from "tsoa";
1010
import { StorageService } from "../services/StorageService.js";
1111
import type { UploadResponse } from "../types/api.js";
12+
import {
13+
FileUploadError,
14+
NoFilesUploadedError,
15+
PartialUploadError,
16+
UploadFailedError,
17+
} from "../lib/uploads/errors.js";
1218

1319
/**
1420
* Controller handling file uploads to IPFS storage
@@ -68,9 +74,9 @@ export class UploadController extends Controller {
6874
@UploadedFiles("files") files?: Express.Multer.File[],
6975
@FormField() jsonData?: string,
7076
): Promise<UploadResponse> {
71-
const storage = await StorageService.init();
72-
7377
try {
78+
const storage = await StorageService.init();
79+
7480
if (jsonData) {
7581
console.debug("Got JSON data for future use");
7682
}
@@ -80,12 +86,7 @@ export class UploadController extends Controller {
8086
);
8187

8288
if (!files || !blobs) {
83-
this.setStatus(400);
84-
return {
85-
success: false,
86-
message: "No files uploaded",
87-
errors: { upload: "No files uploaded" },
88-
};
89+
throw new NoFilesUploadedError();
8990
}
9091

9192
const uploadResults = await Promise.allSettled(
@@ -99,10 +100,11 @@ export class UploadController extends Controller {
99100
fileName: file.originalname,
100101
};
101102
} catch (error) {
102-
throw {
103-
fileName: file.originalname,
104-
error: (error as Error).message,
105-
};
103+
throw new UploadFailedError(
104+
`Failed to upload file`,
105+
file.originalname,
106+
(error as Error).message,
107+
);
106108
}
107109
}),
108110
);
@@ -123,21 +125,32 @@ export class UploadController extends Controller {
123125
(result): result is PromiseRejectedResult =>
124126
result.status === "rejected",
125127
)
126-
.map((result) => result.reason as { fileName: string; error: string });
128+
.map((result) => {
129+
const error = result.reason as UploadFailedError;
130+
return {
131+
fileName: error.fileName,
132+
error: error.errorDetail,
133+
};
134+
});
127135

128136
if (failed.length > 0) {
129-
this.setStatus(failed.length === uploadResults.length ? 500 : 207);
130-
return {
131-
success: false,
132-
message: "Some uploads failed",
133-
data: {
134-
results: successful,
135-
failed: failed.map((f) => ({
136-
fileName: f.fileName,
137-
error: f.error,
138-
})),
139-
},
137+
const data = {
138+
results: successful,
139+
failed: failed.map((f) => ({
140+
fileName: f.fileName,
141+
error: f.error,
142+
})),
140143
};
144+
145+
if (failed.length === uploadResults.length) {
146+
throw new UploadFailedError(
147+
"All uploads failed",
148+
"multiple files",
149+
"None of the files could be uploaded",
150+
);
151+
}
152+
153+
throw new PartialUploadError("Some uploads failed", data);
141154
}
142155

143156
this.setStatus(201);
@@ -150,12 +163,21 @@ export class UploadController extends Controller {
150163
},
151164
};
152165
} catch (error) {
153-
this.setStatus(400);
154-
return {
155-
success: false,
156-
message: "Upload failed",
157-
errors: { upload: (error as Error).message },
158-
};
166+
if (error instanceof FileUploadError) {
167+
this.setStatus(error.code);
168+
return {
169+
success: false,
170+
message: error.message,
171+
...(error.errors && { errors: error.errors }),
172+
...(error instanceof PartialUploadError && { data: error.results }),
173+
};
174+
}
175+
176+
throw new UploadFailedError(
177+
"Upload failed",
178+
"unknown file",
179+
(error as Error).message,
180+
);
159181
}
160182
}
161183
}

src/lib/uploads/errors.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { UploadResponse } from "../../types/api.js";
2+
3+
export class FileUploadError extends Error {
4+
code: number;
5+
public errors: UploadResponse["errors"];
6+
7+
constructor(code: number, message: string) {
8+
super(message);
9+
this.name = "FileUploadError";
10+
this.code = code;
11+
}
12+
}
13+
14+
export class NoFilesUploadedError extends FileUploadError {
15+
constructor() {
16+
super(400, "No files uploaded");
17+
this.name = "NoFilesUploadedError";
18+
this.errors = { upload: "No files uploaded" };
19+
}
20+
}
21+
22+
export class PartialUploadError extends FileUploadError {
23+
constructor(
24+
message: string,
25+
public results: UploadResponse["data"],
26+
) {
27+
super(207, message);
28+
this.name = "PartialUploadError";
29+
}
30+
}
31+
32+
export class UploadFailedError extends FileUploadError {
33+
constructor(
34+
message: string,
35+
public fileName: string,
36+
public errorDetail: string,
37+
) {
38+
super(500, message);
39+
this.name = "UploadFailedError";
40+
this.errors = { upload: message };
41+
}
42+
}

0 commit comments

Comments
 (0)