fix: align ebay route with spec and validate params
This commit is contained in:
@@ -21,8 +21,20 @@ export async function ebayRoute(req: Request): Promise<Response> {
|
|||||||
|
|
||||||
const minPriceParam = reqUrl.searchParams.get("minPrice");
|
const minPriceParam = reqUrl.searchParams.get("minPrice");
|
||||||
const minPrice = minPriceParam ? parseInt(minPriceParam, 10) : undefined;
|
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 maxPriceParam = reqUrl.searchParams.get("maxPrice");
|
||||||
const maxPrice = maxPriceParam ? parseInt(maxPriceParam, 10) : undefined;
|
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 strictMode = reqUrl.searchParams.get("strictMode") === "true";
|
||||||
const buyItNowOnly = reqUrl.searchParams.get("buyItNowOnly") !== "false";
|
const buyItNowOnly = reqUrl.searchParams.get("buyItNowOnly") !== "false";
|
||||||
const canadaOnly = reqUrl.searchParams.get("canadaOnly") !== "false";
|
const canadaOnly = reqUrl.searchParams.get("canadaOnly") !== "false";
|
||||||
@@ -71,28 +83,11 @@ export async function ebayRoute(req: Request): Promise<Response> {
|
|||||||
{ status: 404 },
|
{ status: 404 },
|
||||||
);
|
);
|
||||||
|
|
||||||
let results;
|
const results = hideUnstableResults
|
||||||
if (hideUnstableResults) {
|
? items
|
||||||
const limitedResults =
|
: maxItems !== undefined
|
||||||
maxItems !== undefined
|
? items.slice(0, maxItems)
|
||||||
? items.results.slice(0, maxItems)
|
: items;
|
||||||
: 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.json(results, { status: 200 });
|
return Response.json(results, { status: 200 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -19,10 +19,28 @@ export async function kijijiRoute(req: Request): Promise<Response> {
|
|||||||
|
|
||||||
const maxPagesParam = reqUrl.searchParams.get("maxPages");
|
const maxPagesParam = reqUrl.searchParams.get("maxPages");
|
||||||
const maxPages = maxPagesParam ? parseInt(maxPagesParam, 10) : 5;
|
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 priceMinParam = reqUrl.searchParams.get("priceMin");
|
||||||
const priceMin = priceMinParam ? parseInt(priceMinParam, 10) : undefined;
|
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 priceMaxParam = reqUrl.searchParams.get("priceMax");
|
||||||
const priceMax = priceMaxParam ? parseInt(priceMaxParam, 10) : undefined;
|
const priceMax = priceMaxParam ? parseInt(priceMaxParam, 10) : undefined;
|
||||||
|
if (priceMaxParam && Number.isNaN(priceMax)) {
|
||||||
|
return Response.json(
|
||||||
|
{ message: "Invalid priceMax parameter" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
const hideUnstableResults =
|
const hideUnstableResults =
|
||||||
reqUrl.searchParams.get("unstableFilter") === "true";
|
reqUrl.searchParams.get("unstableFilter") === "true";
|
||||||
|
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ describe("API routes", () => {
|
|||||||
expect(body).toHaveLength(0);
|
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");
|
const { ebayRoute } = await import("../src/routes/ebay");
|
||||||
|
|
||||||
fetchEbayItems.mockImplementation(() =>
|
fetchEbayItems.mockImplementation(() =>
|
||||||
@@ -416,10 +416,8 @@ describe("API routes", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
const total = body.results.length + body.unstableResults.length;
|
|
||||||
expect(total).toBe(4);
|
|
||||||
expect(body.results).toHaveLength(3);
|
expect(body.results).toHaveLength(3);
|
||||||
expect(body.unstableResults).toHaveLength(1);
|
expect(body.unstableResults).toHaveLength(2);
|
||||||
expect(body.results[0].title).toBe("a");
|
expect(body.results[0].title).toBe("a");
|
||||||
expect(body.unstableResults[0].title).toBe("d");
|
expect(body.unstableResults[0].title).toBe("d");
|
||||||
});
|
});
|
||||||
@@ -472,4 +470,74 @@ describe("API routes", () => {
|
|||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
expect(body.message).toBe("Invalid maxItems parameter");
|
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");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user