Skip to content

Commit

Permalink
Always await wrapResponse since it returns a Promise, to protect agai…
Browse files Browse the repository at this point in the history
…nst UnhandledRejection errors (#1494)
  • Loading branch information
ericallam authored Nov 22, 2024
1 parent 4305a23 commit 3792394
Showing 1 changed file with 67 additions and 44 deletions.
111 changes: 67 additions & 44 deletions apps/webapp/app/services/routeBuilders/apiBuilder.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function createLoaderApiRoute<
const authenticationResult = await authenticateApiRequest(request, { allowJWT });

if (!authenticationResult) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Invalid or Missing API key" }, { status: 401 }),
corsStrategy !== "none"
Expand All @@ -89,7 +89,7 @@ export function createLoaderApiRoute<
if (paramsSchema) {
const parsed = paramsSchema.safeParse(params);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Params Error", details: fromZodError(parsed.error).details },
Expand All @@ -106,7 +106,7 @@ export function createLoaderApiRoute<
const searchParams = Object.fromEntries(new URL(request.url).searchParams);
const parsed = searchParamsSchema.safeParse(searchParams);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Query Error", details: fromZodError(parsed.error).details },
Expand All @@ -123,7 +123,7 @@ export function createLoaderApiRoute<
const rawHeaders = Object.fromEntries(request.headers);
const headers = headersSchema.safeParse(rawHeaders);
if (!headers.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Headers Error", details: fromZodError(headers.error).details },
Expand Down Expand Up @@ -154,7 +154,7 @@ export function createLoaderApiRoute<
);

if (!authorizationResult.authorized) {
return wrapResponse(
return await wrapResponse(
request,
json(
{
Expand All @@ -177,16 +177,22 @@ export function createLoaderApiRoute<
authentication: authenticationResult,
request,
});
return wrapResponse(request, result, corsStrategy !== "none");
return await wrapResponse(request, result, corsStrategy !== "none");
} catch (error) {
if (error instanceof Response) {
return wrapResponse(request, error, corsStrategy !== "none");
try {
if (error instanceof Response) {
return await wrapResponse(request, error, corsStrategy !== "none");
}
return await wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
} catch (innerError) {
logger.error("[apiBuilder] Failed to handle error", { error, innerError });

return json({ error: "Internal Server Error" }, { status: 500 });
}
return wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
}
};
}
Expand Down Expand Up @@ -240,7 +246,7 @@ export function createLoaderPATApiRoute<
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);

if (!authenticationResult) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Invalid or Missing API key" }, { status: 401 }),
corsStrategy !== "none"
Expand All @@ -251,7 +257,7 @@ export function createLoaderPATApiRoute<
if (paramsSchema) {
const parsed = paramsSchema.safeParse(params);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Params Error", details: fromZodError(parsed.error).details },
Expand All @@ -268,7 +274,7 @@ export function createLoaderPATApiRoute<
const searchParams = Object.fromEntries(new URL(request.url).searchParams);
const parsed = searchParamsSchema.safeParse(searchParams);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Query Error", details: fromZodError(parsed.error).details },
Expand All @@ -285,7 +291,7 @@ export function createLoaderPATApiRoute<
const rawHeaders = Object.fromEntries(request.headers);
const headers = headersSchema.safeParse(rawHeaders);
if (!headers.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Headers Error", details: fromZodError(headers.error).details },
Expand All @@ -304,17 +310,22 @@ export function createLoaderPATApiRoute<
authentication: authenticationResult,
request,
});
return wrapResponse(request, result, corsStrategy !== "none");
return await wrapResponse(request, result, corsStrategy !== "none");
} catch (error) {
console.error("Error in API route:", error);
if (error instanceof Response) {
return wrapResponse(request, error, corsStrategy !== "none");
try {
if (error instanceof Response) {
return await wrapResponse(request, error, corsStrategy !== "none");
}
return await wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
} catch (innerError) {
logger.error("[apiBuilder] Failed to handle error", { error, innerError });

return json({ error: "Internal Server Error" }, { status: 500 });
}
return wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
}
};
}
Expand Down Expand Up @@ -388,7 +399,7 @@ export function createActionApiRoute<
const authenticationResult = await authenticateApiRequest(request, { allowJWT });

if (!authenticationResult) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Invalid or Missing API key" }, { status: 401 }),
corsStrategy !== "none"
Expand All @@ -407,7 +418,7 @@ export function createActionApiRoute<
if (paramsSchema) {
const parsed = paramsSchema.safeParse(params);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Params Error", details: fromZodError(parsed.error).details },
Expand All @@ -424,7 +435,7 @@ export function createActionApiRoute<
const searchParams = Object.fromEntries(new URL(request.url).searchParams);
const parsed = searchParamsSchema.safeParse(searchParams);
if (!parsed.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Query Error", details: fromZodError(parsed.error).details },
Expand All @@ -441,7 +452,7 @@ export function createActionApiRoute<
const rawHeaders = Object.fromEntries(request.headers);
const headers = headersSchema.safeParse(rawHeaders);
if (!headers.success) {
return wrapResponse(
return await wrapResponse(
request,
json(
{ error: "Headers Error", details: fromZodError(headers.error).details },
Expand All @@ -457,7 +468,7 @@ export function createActionApiRoute<
if (bodySchema) {
const rawBody = await request.text();
if (rawBody.length === 0) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Request body is empty" }, { status: 400 }),
corsStrategy !== "none"
Expand All @@ -467,7 +478,7 @@ export function createActionApiRoute<
const rawParsedJson = safeJsonParse(rawBody);

if (!rawParsedJson) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Invalid JSON" }, { status: 400 }),
corsStrategy !== "none"
Expand All @@ -476,7 +487,7 @@ export function createActionApiRoute<

const body = bodySchema.safeParse(rawParsedJson);
if (!body.success) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: fromZodError(body.error).toString() }, { status: 400 }),
corsStrategy !== "none"
Expand All @@ -497,7 +508,7 @@ export function createActionApiRoute<
});

if (!checkAuthorization(authenticationResult, action, $resource, superScopes)) {
return wrapResponse(
return await wrapResponse(
request,
json({ error: "Unauthorized" }, { status: 403 }),
corsStrategy !== "none"
Expand All @@ -513,24 +524,36 @@ export function createActionApiRoute<
authentication: authenticationResult,
request,
});
return wrapResponse(request, result, corsStrategy !== "none");
return await wrapResponse(request, result, corsStrategy !== "none");
} catch (error) {
if (error instanceof Response) {
return wrapResponse(request, error, corsStrategy !== "none");
try {
if (error instanceof Response) {
return await wrapResponse(request, error, corsStrategy !== "none");
}
return await wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
} catch (innerError) {
logger.error("[apiBuilder] Failed to handle error", { error, innerError });

return json({ error: "Internal Server Error" }, { status: 500 });
}
return wrapResponse(
request,
json({ error: "Internal Server Error" }, { status: 500 }),
corsStrategy !== "none"
);
}
}

return { loader, action };
}

function wrapResponse(request: Request, response: Response, useCors: boolean) {
async function wrapResponse(
request: Request,
response: Response,
useCors: boolean
): Promise<Response> {
return useCors
? apiCors(request, response, { exposedHeaders: ["x-trigger-jwt", "x-trigger-jwt-claims"] })
? await apiCors(request, response, {
exposedHeaders: ["x-trigger-jwt", "x-trigger-jwt-claims"],
})
: response;
}

0 comments on commit 3792394

Please sign in to comment.