← back to Handbag Auth Nextjs

src/app/api/deals/route.ts

82 lines

import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { rateLimit, getClientIp } from '@/lib/rateLimit'
import { addSecurityHeaders } from '@/lib/securityHeaders'
import { validateInput, dealSearchSchema } from '@/lib/validation'

export async function GET(request: NextRequest) {
  try {
    // Rate limiting
    const clientIp = getClientIp(request)
    const rateLimitResult = rateLimit(clientIp, {
      windowMs: 60 * 1000,
      maxRequests: 60, // 60 requests per minute
    })

    if (!rateLimitResult.allowed) {
      const response = NextResponse.json(
        { success: false, error: 'Rate limit exceeded' },
        { status: 429 }
      )
      response.headers.set('Retry-After', String(Math.ceil((rateLimitResult.resetTime - Date.now()) / 1000)))
      addSecurityHeaders(response)
      return response
    }

    // Input validation
    const searchParams = request.nextUrl.searchParams
    const validation = validateInput(dealSearchSchema, {
      minDeal: searchParams.get('minDeal'),
      limit: searchParams.get('limit'),
    })

    if (!validation.success) {
      const response = NextResponse.json(
        { success: false, error: 'Invalid input parameters' },
        { status: 400 }
      )
      addSecurityHeaders(response)
      return response
    }

    const { minDeal, limit } = validation.data

    const deals = await prisma.listing.findMany({
      where: {
        isActive: 1,
        dealAnalysis: {
          isDeal: 1,
          dealPercentage: {
            gte: minDeal
          }
        }
      },
      include: {
        dealAnalysis: true,
      },
      orderBy: {
        dealAnalysis: {
          dealPercentage: 'desc'
        }
      },
      take: limit,
    })

    const response = NextResponse.json({
      success: true,
      count: deals.length,
      deals,
    })
    addSecurityHeaders(response)
    return response
  } catch (error) {
    console.error('Deals API error:', error)
    const response = NextResponse.json(
      { success: false, error: 'Failed to fetch deals' },
      { status: 500 }
    )
    addSecurityHeaders(response)
    return response
  }
}