From 323d6a3dd31fc3f8c6a6843398463fe78ccb0ab1 Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Tue, 22 Jul 2025 06:36:13 -0500 Subject: [PATCH] Add health check and improve database test endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 Improvements: - Add /api/health endpoint for basic API functionality testing - Improve /api/test-db with timeout handling and better error reporting - Add environment variable checks before database operations - Add connection timeouts to prevent function timeouts - Better error handling and logging 🧪 Testing Endpoints: - /api/health - Simple API health check (no DB required) - /api/test-db - Database connectivity test with timeout protection These changes should help identify whether the issue is with API routing, environment variables, or database connectivity. --- api/health.ts | 32 +++++--------- api/test-db.ts | 117 ++++++++++++++++++++++++++++++------------------- 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/api/health.ts b/api/health.ts index 2334f9c..1e21770 100644 --- a/api/health.ts +++ b/api/health.ts @@ -1,27 +1,17 @@ -import { NextRequest, NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server'; 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 }) - } - return new NextResponse(JSON.stringify({ - status: 'healthy', - service: 'TCG Vault API', - version: '1.0.0', - timestamp: new Date().toISOString() + success: true, + message: 'API is working!', + timestamp: new Date().toISOString(), + environment: process.env.NODE_ENV || 'unknown', + has_database_url: !!process.env.DATABASE_URL, + has_jwt_secret: !!process.env.JWT_SECRET, + method: req.method, + url: req.url }), { status: 200, - headers: { - ...headers, - 'Content-Type': 'application/json', - }, - }) + headers: { 'Content-Type': 'application/json' }, + }); } diff --git a/api/test-db.ts b/api/test-db.ts index 553737e..ae3bc9c 100644 --- a/api/test-db.ts +++ b/api/test-db.ts @@ -1,11 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; import { Pool } from 'pg'; -const pool = new Pool({ - connectionString: process.env.DATABASE_URL, - ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, -}); - export default async function handler(req: NextRequest) { if (req.method !== 'GET') { return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), { @@ -14,57 +9,73 @@ export default async function handler(req: NextRequest) { }); } - const client = await pool.connect(); + // Check environment variables first + if (!process.env.DATABASE_URL) { + return new NextResponse(JSON.stringify({ + success: false, + error: 'DATABASE_URL environment variable not set', + environment: process.env.NODE_ENV || 'unknown' + }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }); + } + + const pool = new Pool({ + connectionString: process.env.DATABASE_URL, + ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, + connectionTimeoutMillis: 10000, // 10 seconds + query_timeout: 10000, // 10 seconds + }); + + let client: any; try { console.log('Testing database connection...'); - - // Test basic connection - const result = await client.query('SELECT NOW() as current_time, version() as postgres_version'); - // Check if users table exists - const tableCheck = await client.query(` - SELECT EXISTS ( - SELECT FROM information_schema.tables - WHERE table_schema = 'public' - AND table_name = 'users' - ) as users_table_exists; - `); + // Set a timeout for the entire operation + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => reject(new Error('Database operation timed out')), 15000); + }); - // Check if cards table exists - const cardsCheck = await client.query(` - SELECT EXISTS ( - SELECT FROM information_schema.tables - WHERE table_schema = 'public' - AND table_name = 'cards' - ) as cards_table_exists; - `); + const dbOperation = async () => { + client = await pool.connect(); + + // Test basic connection + const result = await client.query('SELECT NOW() as current_time, version() as postgres_version'); + + // Check if users table exists + const tableCheck = await client.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'users' + ) as users_table_exists; + `); - // Get table counts - let userCount = 0; - let cardCount = 0; + // Check if cards table exists + const cardsCheck = await client.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'cards' + ) as cards_table_exists; + `); - if (tableCheck.rows[0].users_table_exists) { - const userCountResult = await client.query('SELECT COUNT(*) as count FROM users'); - userCount = parseInt(userCountResult.rows[0].count); - } + return { + current_time: result.rows[0].current_time, + postgres_version: result.rows[0].postgres_version, + users_table_exists: tableCheck.rows[0].users_table_exists, + cards_table_exists: cardsCheck.rows[0].cards_table_exists + }; + }; - if (cardsCheck.rows[0].cards_table_exists) { - const cardCountResult = await client.query('SELECT COUNT(*) as count FROM cards'); - cardCount = parseInt(cardCountResult.rows[0].count); - } + const dbResult = await Promise.race([dbOperation(), timeoutPromise]); return new NextResponse(JSON.stringify({ success: true, message: 'Database connection successful', - database_info: { - current_time: result.rows[0].current_time, - postgres_version: result.rows[0].postgres_version, - users_table_exists: tableCheck.rows[0].users_table_exists, - cards_table_exists: cardsCheck.rows[0].cards_table_exists, - user_count: userCount, - card_count: cardCount - } + database_info: dbResult }), { status: 200, headers: { 'Content-Type': 'application/json' }, @@ -75,12 +86,26 @@ export default async function handler(req: NextRequest) { return new NextResponse(JSON.stringify({ success: false, error: 'Database connection failed', - details: (error as Error).message + details: (error as Error).message, + database_url_exists: !!process.env.DATABASE_URL, + database_url_preview: process.env.DATABASE_URL ? + process.env.DATABASE_URL.substring(0, 20) + '...' : 'not set' }), { status: 500, headers: { 'Content-Type': 'application/json' }, }); } finally { - client.release(); + if (client) { + try { + client.release(); + } catch (e) { + console.error('Error releasing client:', e); + } + } + try { + await pool.end(); + } catch (e) { + console.error('Error ending pool:', e); + } } } \ No newline at end of file