From 8500af5cfe8817c9e54cab14dc3ad446db7385ad Mon Sep 17 00:00:00 2001 From: aoi-dev-0411 Date: Sat, 11 Apr 2026 11:59:43 +0900 Subject: [PATCH 1/2] feat: display friendly error messages on API failure Closes #34 --- app/api/compare/route.ts | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/app/api/compare/route.ts b/app/api/compare/route.ts index 809b290..66ca01a 100644 --- a/app/api/compare/route.ts +++ b/app/api/compare/route.ts @@ -4,13 +4,38 @@ import { calculateUserScore } from "../../../lib/score"; export const runtime = "nodejs"; +function classifyError(error: any): { message: string; status: number } { + const msg = error?.message ?? ""; + + if (msg === "User not found") { + return { message: "GitHub user not found. Please check the username and try again.", status: 404 }; + } + + if (msg.includes("rate limit") || error?.status === 403) { + return { + message: "GitHub API rate limit exceeded. Please wait a few minutes and try again.", + status: 429, + }; + } + + if (msg.includes("Bad credentials") || error?.status === 401) { + return { message: "GitHub API authentication error. Please contact the administrator.", status: 500 }; + } + + if (error?.code === "ENOTFOUND" || error?.code === "ETIMEDOUT") { + return { message: "Unable to reach GitHub. Please check your connection and try again.", status: 503 }; + } + + return { message: "Something went wrong while fetching data. Please try again later.", status: 500 }; +} + export async function GET(request: Request) { const { searchParams } = new URL(request.url); const usernames = searchParams.getAll("username"); if (usernames.length === 0) { return NextResponse.json( - { success: false, error: "provide at least one username param" }, + { success: false, error: "Please provide at least one GitHub username." }, { status: 400 } ); } @@ -36,13 +61,7 @@ export async function GET(request: Request) { return NextResponse.json({ success: true, users: results }); } catch (error: any) { console.error("GitHub score error:", error); - const message = - error?.message === "User not found" - ? "GitHub user not found" - : "Failed to calculate score"; - return NextResponse.json( - { success: false, error: message }, - { status: 500 } - ); + const { message, status } = classifyError(error); + return NextResponse.json({ success: false, error: message }, { status }); } } From 97b9d9ee7ee1d402fce0d6058caa796f289a51ae Mon Sep 17 00:00:00 2001 From: aoi-dev-0411 Date: Sat, 11 Apr 2026 12:00:03 +0900 Subject: [PATCH 2/2] refactor: pass error to CompareForm and remove duplicate error display --- app/page.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index ed3a79e..1562228 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -47,7 +47,7 @@ export default function HomePage() { setData({ user1: body.users[0], user2: body.users[1] }); } } catch (err: any) { - setError(err.message || "Failed to fetch"); + setError(err.message || "An unexpected error occurred. Please try again."); } finally { setLoading(false); } @@ -84,14 +84,10 @@ export default function HomePage() { reset={reset} swapUsers={swapUsers} data={data} + error={error} /> {loading && skeleton} - {error && ( -
- {error} -
- )} {data && }