fix: strictly parse route integers

This commit is contained in:
2026-04-29 00:12:26 -04:00
parent d178f9c9cb
commit 3ea6ee3938
5 changed files with 171 additions and 105 deletions

View File

@@ -1,5 +1,10 @@
import { fetchKijijiItems } from "@marketplace-scrapers/core";
import { logger } from "../logger";
import {
emptySearchResponse,
getRequiredSearchQuery,
parseNonNegativeIntegerParam,
} from "./helpers";
/**
* GET /api/kijiji?q={query}
@@ -8,39 +13,32 @@ import { logger } from "../logger";
export async function kijijiRoute(req: Request): Promise<Response> {
const reqUrl = new URL(req.url);
const SEARCH_QUERY =
req.headers.get("query") || reqUrl.searchParams.get("q") || null;
if (!SEARCH_QUERY)
return Response.json(
{
message: "Request didn't have 'query' header or 'q' search parameter!",
},
{ status: 400 },
);
const SEARCH_QUERY = getRequiredSearchQuery(req);
if (SEARCH_QUERY instanceof Response) {
return SEARCH_QUERY;
}
const maxPagesParam = reqUrl.searchParams.get("maxPages");
const maxPages = maxPagesParam ? parseInt(maxPagesParam, 10) : 5;
if (maxPagesParam && (Number.isNaN(maxPages) || maxPages < 0)) {
return Response.json(
{ message: "Invalid maxPages parameter" },
{ status: 400 },
);
const maxPages = parseNonNegativeIntegerParam(
reqUrl.searchParams,
"maxPages",
5,
);
if (maxPages instanceof Response) {
return maxPages;
}
const priceMinParam = reqUrl.searchParams.get("priceMin");
const priceMin = priceMinParam ? parseInt(priceMinParam, 10) : undefined;
if (priceMinParam && (Number.isNaN(priceMin) || (priceMin ?? 0) < 0)) {
return Response.json(
{ message: "Invalid priceMin parameter" },
{ status: 400 },
);
const priceMin = parseNonNegativeIntegerParam(
reqUrl.searchParams,
"priceMin",
);
if (priceMin instanceof Response) {
return priceMin;
}
const priceMaxParam = reqUrl.searchParams.get("priceMax");
const priceMax = priceMaxParam ? parseInt(priceMaxParam, 10) : undefined;
if (priceMaxParam && (Number.isNaN(priceMax) || (priceMax ?? 0) < 0)) {
return Response.json(
{ message: "Invalid priceMax parameter" },
{ status: 400 },
);
const priceMax = parseNonNegativeIntegerParam(
reqUrl.searchParams,
"priceMax",
);
if (priceMax instanceof Response) {
return priceMax;
}
const hideUnstableResults =
reqUrl.searchParams.get("unstableFilter") === "true";
@@ -75,10 +73,7 @@ export async function kijijiRoute(req: Request): Promise<Response> {
{ hideUnstableResults: true },
);
if (items.results.length === 0 && items.unstableResults.length === 0) {
return Response.json(
{ message: "Search didn't return any results!" },
{ status: 404 },
);
return emptySearchResponse();
}
return Response.json(items, { status: 200 });
}
@@ -90,11 +85,9 @@ export async function kijijiRoute(req: Request): Promise<Response> {
searchOptions,
{},
);
if (!items || items.length === 0)
return Response.json(
{ message: "Search didn't return any results!" },
{ status: 404 },
);
if (!items || items.length === 0) {
return emptySearchResponse();
}
return Response.json(items, { status: 200 });
} catch (error) {
logger.error("Kijiji scraping error:", error);