All files / src/app/api/reviews route.ts

98.21% Statements 110/112
95% Branches 19/20
100% Functions 2/2
98.21% Lines 110/112

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 1131x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 5x 5x 5x 5x 5x 5x 5x 5x 5x 4x 4x 4x 4x 4x 4x 4x 4x 8x 2x 2x 2x 2x 2x 2x 2x 2x 3x 1x 1x 8x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 2x 2x 3x 5x     3x 3x 2x 2x 2x 1x 1x  
import { NextRequest, NextResponse } from 'next/server';
import { Session } from "next-auth";
import {
  createReview,
  getProductReviews,
  getProductRating,
  getUserReviews } from "@/lib/ecommerce";
import {
  withErrorHandling,
  withUser,
  successResponse,
  ApiError,
  ApiSuccessResponse } from "@/lib/api";
import { RouteContext } from "@/lib/api/middleware";
import type { AuthenticatedUser } from '@/lib/api/middleware/types';
 
interface ReviewsResponse {
  reviews?: unknown[];
  data?: unknown[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    pages: number;
  };
  rating?: unknown;
}
 
/**
 * GET /api/reviews
 * Get reviews with filters
 *
 * Query Parameters:
 * - productId: Filter by product
 * - userId: Filter by user
 * - page: Page number
 * - limit: Results per page
 * - rating: Filter by rating (1-5)
 * - sortBy: newest, helpful, rating_high, rating_low
 */
async function handleGet(
  request: NextRequest
): Promise<NextResponse<ApiSuccessResponse<ReviewsResponse>>> {
  const searchParams = request.nextUrl.searchParams;
  const productId = searchParams.get("productId");
  const userId = searchParams.get("userId");
  const page = searchParams.get("page") ? parseInt(searchParams.get("page")!) : 1;
  const limit = searchParams.get("limit") ? parseInt(searchParams.get("limit")!) : 10;
  const rating = searchParams.get("rating") ? parseInt(searchParams.get("rating")!) : undefined;
  const sortBy = (searchParams.get("sortBy") || "newest") as "newest" | "helpful" | "rating_high" | "rating_low";
 
  if (productId) {
    // Get reviews for a product
    const { reviews, pagination } = await getProductReviews(
      parseInt(productId),
      {
        page,
        limit,
        rating,
        sortBy}
    );
 
    // Get product rating summary
    const ratingData = await getProductRating(parseInt(productId));
 
    return successResponse({
      data: reviews,
      pagination,
      rating: ratingData});
  } else if (userId) {
    // Get reviews by user
    const { reviews, pagination } = await getUserReviews(parseInt(userId), {
      page,
      limit});
 
    return successResponse({
      data: reviews,
      pagination});
  } else {
    throw ApiError.validation("Either productId or userId is required");
  }
}
 
export const GET = withErrorHandling(handleGet);
 
/**
 * POST /api/reviews
 * Create a new review (requires authentication)
 */
async function handlePost(
  request: NextRequest,
  _context: RouteContext | undefined,
  _session: Session,
  user: AuthenticatedUser
): Promise<NextResponse> {
  const body = await request.json();
  const { productId, rating, comment } = body;
 
  if (!productId || !rating) {
    throw ApiError.validation("productId and rating are required");
  }
 
  if (rating < 1 || rating > 5) {
    throw ApiError.validation("Rating must be between 1 and 5");
  }
 
  const review = await createReview(productId, user.id, rating, comment);
 
  return successResponse(review);
}
 
export const POST = withErrorHandling(withUser(handlePost));