Skip to content

Commit

Permalink
fix: improve error handling in utapi (#1125)
Browse files Browse the repository at this point in the history
  • Loading branch information
juliusmarminge authored Jan 10, 2025
1 parent f08b20e commit aab8ab6
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .changeset/curvy-rings-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"uploadthing": patch
---

fix: improve error handling in utapi

sometimes errors got silently ignored when they shouldn't have
4 changes: 3 additions & 1 deletion packages/uploadthing/src/_internal/upload-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { UploadThingError } from "@uploadthing/shared";

import { version } from "../../package.json";
import type { FileEsque } from "../sdk/types";
import { logHttpClientError } from "./logger";
import type { UploadPutResult } from "./types";

export const uploadWithoutProgress = (
Expand All @@ -14,7 +15,7 @@ export const uploadWithoutProgress = (
) =>
Effect.gen(function* () {
const formData = new FormData();
formData.append("file", file as Blob); // File data **MUST GO LAST**
formData.append("file", file as Blob);

const httpClient = (yield* HttpClient.HttpClient).pipe(
HttpClient.filterStatusOk,
Expand All @@ -24,6 +25,7 @@ export const uploadWithoutProgress = (
HttpClientRequest.setHeader("Range", "bytes=0-"),
HttpClientRequest.setHeader("x-uploadthing-version", version),
httpClient.execute,
Effect.tapError(logHttpClientError("Failed to upload file")),
Effect.mapError(
(e) =>
new UploadThingError({
Expand Down
6 changes: 6 additions & 0 deletions packages/uploadthing/src/sdk/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export const uploadFile = (
opts.contentDisposition ?? "inline",
opts.acl,
).pipe(
Effect.catchTag("UploadThingError", (e) =>
Effect.fail(UploadThingError.toObject(e)),
),
Effect.catchTag("ConfigError", () =>
Effect.fail({
code: "INVALID_SERVER_CONFIG",
Expand All @@ -128,6 +131,9 @@ export const uploadFile = (
),
);
const response = yield* uploadWithoutProgress(file, presigned).pipe(
Effect.catchTag("UploadThingError", (e) =>
Effect.fail(UploadThingError.toObject(e)),
),
Effect.catchTag("ResponseError", (e) =>
Effect.fail({
code: "UPLOAD_FAILED",
Expand Down
2 changes: 1 addition & 1 deletion packages/uploadthing/test/__test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const baseHeaders = {
* Call this in each MSW handler to spy on the request
* and provide an easy way to assert on the request
*/
const callRequestSpy = async (request: StrictRequest<any>) =>
export const callRequestSpy = async (request: StrictRequest<any>) =>
requestSpy(new URL(request.url).toString(), {
method: request.method,
headers: Object.fromEntries(request.headers),
Expand Down
41 changes: 41 additions & 0 deletions packages/uploadthing/test/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { UTApi, UTFile } from "../src/sdk";
import type { UploadFileResult } from "../src/sdk/types";
import {
API_URL,
callRequestSpy,
handlers,
INGEST_URL,
requestSpy,
Expand Down Expand Up @@ -97,6 +98,46 @@ describe("uploadFiles", () => {
expect.objectContaining({ method: "PUT" }),
);
});

it("gracefully handles failed requests", async () => {
const mockedIngestUrl = "https://mocked.ingest.uploadthing.com";
msw.use(
http.all<{ key: string }>(
`${mockedIngestUrl}/:key`,
async ({ request }) => {
await callRequestSpy(request);
return HttpResponse.json({ error: "Upload failed" }, { status: 400 });
},
),
);

const utapi = new UTApi({
token: testToken.encoded,
/**
* Explicitly set the ingestUrl to the mocked one
* to ensure the request is made to the mocked ingest
* endpoint that yields a 400 error.
*/
ingestUrl: mockedIngestUrl,
});
const result = await utapi.uploadFiles(fooFile);
expect(result).toStrictEqual({
data: null,
error: {
code: "UPLOAD_FAILED",
data: undefined,
message: "Failed to upload file",
},
});

expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith(
expect.stringContaining(mockedIngestUrl),
expect.objectContaining({ method: "PUT" }),
);

msw.use(...handlers);
});
});

describe("uploadFilesFromUrl", () => {
Expand Down

0 comments on commit aab8ab6

Please sign in to comment.