deckhearth/api/v1/cards/[id].ts
Randall Stillwell 6f40a5058d Fix Node.js 18 compatibility for Vercel deployment
- Switch from @neondatabase/serverless to standard 'pg' client for Node.js 18 support
- Update Node.js version to 18.x as required by Vercel
- Replace Neon template literals with standard parameterized queries
- Add proper connection pooling and SSL configuration for production
- All API endpoints updated: /api/v1/cards/, /api/v1/cards/[id], /api/migrate
- Build tested and working successfully
2025-07-21 16:08:45 -05:00

122 lines
3.3 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { Pool } from 'pg'
// Create PostgreSQL connection pool
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
})
interface Card {
id: number
name: string
set_name?: string
set_code?: string
card_number?: string
rarity?: string
game: string
mana_cost?: string
cmc?: number
card_type?: string
colors?: string[]
oracle_text?: string
flavor_text?: string
power?: string
toughness?: string
artist?: string
image_url?: string
stock_image_url?: string
artwork_crop_coords?: any
current_price?: number
market_price?: number
verified: boolean
created_at?: string
updated_at?: string
}
export default async function handler(req: NextRequest) {
// Enable CORS
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}
if (req.method === 'OPTIONS') {
return new NextResponse(null, { status: 200, headers })
}
if (req.method !== 'GET') {
return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), {
status: 405,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
}
try {
// Extract card ID from URL
const url = new URL(req.url)
const pathParts = url.pathname.split('/')
const cardId = pathParts[pathParts.length - 1]
if (!cardId || isNaN(parseInt(cardId))) {
return new NextResponse(JSON.stringify({ error: 'Invalid card ID' }), {
status: 400,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
}
// Query the database for the specific card
const client = await pool.connect()
try {
const result = await client.query('SELECT * FROM cards WHERE id = $1', [parseInt(cardId)])
if (result.rows.length === 0) {
return new NextResponse(JSON.stringify({ error: 'Card not found' }), {
status: 404,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
}
// Transform the result to match expected format
const card = {
...result.rows[0],
colors: result.rows[0].colors ? (typeof result.rows[0].colors === 'string' ? JSON.parse(result.rows[0].colors) : result.rows[0].colors) : null,
artwork_crop_coords: result.rows[0].artwork_crop_coords ?
(typeof result.rows[0].artwork_crop_coords === 'string' ? JSON.parse(result.rows[0].artwork_crop_coords) : result.rows[0].artwork_crop_coords) : null
}
return new NextResponse(JSON.stringify(card), {
status: 200,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
} finally {
client.release()
}
} catch (error) {
console.error('API Error:', error)
return new NextResponse(JSON.stringify({
error: 'Internal server error',
details: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined
}), {
status: 500,
headers: {
...headers,
'Content-Type': 'application/json',
},
})
}
}