trptk/app/api/cart/route.ts
2026-02-24 17:14:07 +01:00

58 lines
2 KiB
TypeScript

import { NextResponse } from "next/server";
import { createCart, getCart } from "@/lib/medusa";
import { headers } from "next/headers";
import { createRateLimiter, getClientIp } from "@/lib/rateLimit";
import { isNonEmptyString, checkCsrf, isValidMedusaId, badRequest } from "@/lib/apiUtils";
import { getAuthToken } from "@/lib/auth";
// 10 cart creations per IP per 15 minutes
const limiter = createRateLimiter({ windowMs: 15 * 60 * 1000, maxRequests: 10 });
// POST /api/cart — create a new cart
export async function POST() {
const csrfError = await checkCsrf();
if (csrfError) return csrfError;
const hdrs = await headers();
const ip = getClientIp(hdrs);
const limit = limiter.check(`cart:${ip}`);
if (!limit.allowed) {
return NextResponse.json(
{ error: "Too many requests. Please try again later." },
{ status: 429, headers: { "Retry-After": String(Math.ceil(limit.retryAfterMs / 1000)) } },
);
}
// Pass auth token so Medusa associates the cart with the logged-in customer
const authToken = (await getAuthToken()) ?? undefined;
try {
const cart = await createCart(authToken);
return NextResponse.json(cart);
} catch (e) {
console.error("[cart:create]", (e as Error).message);
return NextResponse.json({ error: "Failed to create cart" }, { status: 500 });
}
}
// GET /api/cart?id=cart_xxx — fetch an existing cart
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");
if (!isNonEmptyString(id)) {
return badRequest("Missing cart id");
}
if (!isValidMedusaId(id)) {
return badRequest("Invalid cart ID format");
}
try {
const cart = await getCart(id);
if (!cart) {
return NextResponse.json({ error: "Cart not found" }, { status: 404 });
}
return NextResponse.json(cart);
} catch (e) {
console.error("[cart:get]", (e as Error).message);
return NextResponse.json({ error: "Failed to fetch cart" }, { status: 500 });
}
}