Add health check and improve database test endpoint
🔧 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.
This commit is contained in:
parent
2f4336889d
commit
323d6a3dd3
2 changed files with 82 additions and 67 deletions
|
|
@ -1,27 +1,17 @@
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
export default async function handler(req: NextRequest) {
|
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({
|
return new NextResponse(JSON.stringify({
|
||||||
status: 'healthy',
|
success: true,
|
||||||
service: 'TCG Vault API',
|
message: 'API is working!',
|
||||||
version: '1.0.0',
|
timestamp: new Date().toISOString(),
|
||||||
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,
|
status: 200,
|
||||||
headers: {
|
headers: { 'Content-Type': 'application/json' },
|
||||||
...headers,
|
});
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
115
api/test-db.ts
115
api/test-db.ts
|
|
@ -1,11 +1,6 @@
|
||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import { Pool } from 'pg';
|
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) {
|
export default async function handler(req: NextRequest) {
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), {
|
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 {
|
try {
|
||||||
console.log('Testing database connection...');
|
console.log('Testing database connection...');
|
||||||
|
|
||||||
// Test basic connection
|
// Set a timeout for the entire operation
|
||||||
const result = await client.query('SELECT NOW() as current_time, version() as postgres_version');
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
|
setTimeout(() => reject(new Error('Database operation timed out')), 15000);
|
||||||
|
});
|
||||||
|
|
||||||
// Check if users table exists
|
const dbOperation = async () => {
|
||||||
const tableCheck = await client.query(`
|
client = await pool.connect();
|
||||||
SELECT EXISTS (
|
|
||||||
SELECT FROM information_schema.tables
|
|
||||||
WHERE table_schema = 'public'
|
|
||||||
AND table_name = 'users'
|
|
||||||
) as users_table_exists;
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Check if cards table exists
|
// Test basic connection
|
||||||
const cardsCheck = await client.query(`
|
const result = await client.query('SELECT NOW() as current_time, version() as postgres_version');
|
||||||
SELECT EXISTS (
|
|
||||||
SELECT FROM information_schema.tables
|
|
||||||
WHERE table_schema = 'public'
|
|
||||||
AND table_name = 'cards'
|
|
||||||
) as cards_table_exists;
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Get table counts
|
// Check if users table exists
|
||||||
let userCount = 0;
|
const tableCheck = await client.query(`
|
||||||
let cardCount = 0;
|
SELECT EXISTS (
|
||||||
|
SELECT FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'users'
|
||||||
|
) as users_table_exists;
|
||||||
|
`);
|
||||||
|
|
||||||
if (tableCheck.rows[0].users_table_exists) {
|
// Check if cards table exists
|
||||||
const userCountResult = await client.query('SELECT COUNT(*) as count FROM users');
|
const cardsCheck = await client.query(`
|
||||||
userCount = parseInt(userCountResult.rows[0].count);
|
SELECT EXISTS (
|
||||||
}
|
SELECT FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'cards'
|
||||||
|
) as cards_table_exists;
|
||||||
|
`);
|
||||||
|
|
||||||
if (cardsCheck.rows[0].cards_table_exists) {
|
return {
|
||||||
const cardCountResult = await client.query('SELECT COUNT(*) as count FROM cards');
|
current_time: result.rows[0].current_time,
|
||||||
cardCount = parseInt(cardCountResult.rows[0].count);
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const dbResult = await Promise.race([dbOperation(), timeoutPromise]);
|
||||||
|
|
||||||
return new NextResponse(JSON.stringify({
|
return new NextResponse(JSON.stringify({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Database connection successful',
|
message: 'Database connection successful',
|
||||||
database_info: {
|
database_info: dbResult
|
||||||
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
|
|
||||||
}
|
|
||||||
}), {
|
}), {
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|
@ -75,12 +86,26 @@ export default async function handler(req: NextRequest) {
|
||||||
return new NextResponse(JSON.stringify({
|
return new NextResponse(JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Database connection failed',
|
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,
|
status: 500,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
});
|
});
|
||||||
} finally {
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue