fix: align ebay route with spec and validate params

This commit is contained in:
2026-04-27 09:56:39 -04:00
parent 77b9fc9934
commit a1af5d2630
3 changed files with 107 additions and 26 deletions

View File

@@ -21,8 +21,20 @@ export async function ebayRoute(req: Request): Promise<Response> {
const minPriceParam = reqUrl.searchParams.get("minPrice");
const minPrice = minPriceParam ? parseInt(minPriceParam, 10) : undefined;
if (minPriceParam && Number.isNaN(minPrice)) {
return Response.json(
{ message: "Invalid minPrice parameter" },
{ status: 400 },
);
}
const maxPriceParam = reqUrl.searchParams.get("maxPrice");
const maxPrice = maxPriceParam ? parseInt(maxPriceParam, 10) : undefined;
if (maxPriceParam && Number.isNaN(maxPrice)) {
return Response.json(
{ message: "Invalid maxPrice parameter" },
{ status: 400 },
);
}
const strictMode = reqUrl.searchParams.get("strictMode") === "true";
const buyItNowOnly = reqUrl.searchParams.get("buyItNowOnly") !== "false";
const canadaOnly = reqUrl.searchParams.get("canadaOnly") !== "false";
@@ -71,28 +83,11 @@ export async function ebayRoute(req: Request): Promise<Response> {
{ status: 404 },
);
let results;
if (hideUnstableResults) {
const limitedResults =
maxItems !== undefined
? items.results.slice(0, maxItems)
: items.results;
const remainingSlots =
maxItems !== undefined
? Math.max(0, maxItems - limitedResults.length)
: undefined;
const limitedUnstable =
remainingSlots !== undefined
? items.unstableResults.slice(0, remainingSlots)
: items.unstableResults;
results = {
results: limitedResults,
unstableResults: limitedUnstable,
};
} else {
results =
maxItems !== undefined ? items.slice(0, maxItems) : items;
}
const results = hideUnstableResults
? items
: maxItems !== undefined
? items.slice(0, maxItems)
: items;
return Response.json(results, { status: 200 });
} catch (error) {

View File

@@ -19,10 +19,28 @@ export async function kijijiRoute(req: Request): Promise<Response> {
const maxPagesParam = reqUrl.searchParams.get("maxPages");
const maxPages = maxPagesParam ? parseInt(maxPagesParam, 10) : 5;
if (maxPagesParam && Number.isNaN(maxPages)) {
return Response.json(
{ message: "Invalid maxPages parameter" },
{ status: 400 },
);
}
const priceMinParam = reqUrl.searchParams.get("priceMin");
const priceMin = priceMinParam ? parseInt(priceMinParam, 10) : undefined;
if (priceMinParam && Number.isNaN(priceMin)) {
return Response.json(
{ message: "Invalid priceMin parameter" },
{ status: 400 },
);
}
const priceMaxParam = reqUrl.searchParams.get("priceMax");
const priceMax = priceMaxParam ? parseInt(priceMaxParam, 10) : undefined;
if (priceMaxParam && Number.isNaN(priceMax)) {
return Response.json(
{ message: "Invalid priceMax parameter" },
{ status: 400 },
);
}
const hideUnstableResults =
reqUrl.searchParams.get("unstableFilter") === "true";

View File

@@ -399,7 +399,7 @@ describe("API routes", () => {
expect(body).toHaveLength(0);
});
test("ebayRoute limits total items with maxItems in unstable mode", async () => {
test("ebayRoute passes through scraper payload unchanged in unstable mode", async () => {
const { ebayRoute } = await import("../src/routes/ebay");
fetchEbayItems.mockImplementation(() =>
@@ -416,10 +416,8 @@ describe("API routes", () => {
);
const body = await response.json();
const total = body.results.length + body.unstableResults.length;
expect(total).toBe(4);
expect(body.results).toHaveLength(3);
expect(body.unstableResults).toHaveLength(1);
expect(body.unstableResults).toHaveLength(2);
expect(body.results[0].title).toBe("a");
expect(body.unstableResults[0].title).toBe("d");
});
@@ -472,4 +470,74 @@ describe("API routes", () => {
const body = await response.json();
expect(body.message).toBe("Invalid maxItems parameter");
});
test("ebayRoute returns 400 for invalid minPrice", async () => {
const { ebayRoute } = await import("../src/routes/ebay");
const response = await ebayRoute(
new Request(
"http://localhost/api/ebay?q=laptop&minPrice=abc",
),
);
expect(response.status).toBe(400);
const body = await response.json();
expect(body.message).toBe("Invalid minPrice parameter");
});
test("ebayRoute returns 400 for invalid maxPrice", async () => {
const { ebayRoute } = await import("../src/routes/ebay");
const response = await ebayRoute(
new Request(
"http://localhost/api/ebay?q=laptop&maxPrice=abc",
),
);
expect(response.status).toBe(400);
const body = await response.json();
expect(body.message).toBe("Invalid maxPrice parameter");
});
test("kijijiRoute returns 400 for invalid maxPages", async () => {
const { kijijiRoute } = await import("../src/routes/kijiji");
const response = await kijijiRoute(
new Request(
"http://localhost/api/kijiji?q=laptop&maxPages=abc",
),
);
expect(response.status).toBe(400);
const body = await response.json();
expect(body.message).toBe("Invalid maxPages parameter");
});
test("kijijiRoute returns 400 for invalid priceMin", async () => {
const { kijijiRoute } = await import("../src/routes/kijiji");
const response = await kijijiRoute(
new Request(
"http://localhost/api/kijiji?q=laptop&priceMin=abc",
),
);
expect(response.status).toBe(400);
const body = await response.json();
expect(body.message).toBe("Invalid priceMin parameter");
});
test("kijijiRoute returns 400 for invalid priceMax", async () => {
const { kijijiRoute } = await import("../src/routes/kijiji");
const response = await kijijiRoute(
new Request(
"http://localhost/api/kijiji?q=laptop&priceMax=abc",
),
);
expect(response.status).toBe(400);
const body = await response.json();
expect(body.message).toBe("Invalid priceMax parameter");
});
});