← 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
}
}