Merge pull request #1223 from bglglzd/fix/public-api-prompts-pagination
Add validation and caps for public /api/prompts pagination
This commit is contained in:
@@ -87,6 +87,36 @@ describe("GET /api/prompts", () => {
|
||||
expect(data.perPage).toBe(24);
|
||||
});
|
||||
|
||||
it("should fall back to defaults when pagination parameters are malformed", async () => {
|
||||
vi.mocked(db.prompt.findMany).mockResolvedValue([]);
|
||||
vi.mocked(db.prompt.count).mockResolvedValue(0);
|
||||
|
||||
const request = new Request(
|
||||
"http://localhost:3000/api/prompts?page=not-a-number&perPage=bad-value"
|
||||
);
|
||||
const response = await GET(request);
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(data.page).toBe(1);
|
||||
expect(data.perPage).toBe(24);
|
||||
});
|
||||
|
||||
it("should clamp pagination parameters to configured maximums", async () => {
|
||||
vi.mocked(db.prompt.findMany).mockResolvedValue([]);
|
||||
vi.mocked(db.prompt.count).mockResolvedValue(0);
|
||||
|
||||
const request = new Request(
|
||||
"http://localhost:3000/api/prompts?page=20000&perPage=999"
|
||||
);
|
||||
const response = await GET(request);
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(data.page).toBe(10000);
|
||||
expect(data.perPage).toBe(100);
|
||||
});
|
||||
|
||||
it("should filter by type", async () => {
|
||||
vi.mocked(db.prompt.findMany).mockResolvedValue([]);
|
||||
vi.mocked(db.prompt.count).mockResolvedValue(0);
|
||||
|
||||
@@ -306,11 +306,33 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
// List prompts (for API access)
|
||||
const MAX_API_PER_PAGE = 100;
|
||||
const DEFAULT_API_PER_PAGE = 24;
|
||||
const MAX_API_PAGE = 10000;
|
||||
const DEFAULT_API_PAGE = 1;
|
||||
|
||||
const paginationQuerySchema = z.object({
|
||||
page: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.transform((value) => Math.min(value, MAX_API_PAGE))
|
||||
.catch(DEFAULT_API_PAGE),
|
||||
perPage: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.transform((value) => Math.min(value, MAX_API_PER_PAGE))
|
||||
.catch(DEFAULT_API_PER_PAGE),
|
||||
});
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const page = parseInt(searchParams.get("page") || "1");
|
||||
const perPage = parseInt(searchParams.get("perPage") || "24");
|
||||
const { page, perPage } = paginationQuerySchema.parse({
|
||||
page: searchParams.get("page"),
|
||||
perPage: searchParams.get("perPage"),
|
||||
});
|
||||
const type = searchParams.get("type");
|
||||
const categoryId = searchParams.get("category");
|
||||
const tag = searchParams.get("tag");
|
||||
|
||||
Reference in New Issue
Block a user