Files
vuelato/server/api/destination-image.get.ts
Alejandro Martinez b8906efc80
Some checks failed
ci / ci (22, ubuntu-latest) (push) Has been cancelled
Initial commit: Vuelato - buscador de vuelos
Nuxt 4 + Supabase + Flightics API. Incluye búsqueda de vuelos,
inspiraciones, watchlist, tracking de precios y mapa interactivo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:37:06 +02:00

65 lines
1.7 KiB
TypeScript

import { serverSupabaseServiceRole } from '#supabase/server'
export default defineEventHandler(async (event) => {
const { city } = getQuery(event)
if (!city || typeof city !== 'string') {
throw createError({ statusCode: 400, message: 'city is required' })
}
const cityKey = city.trim().toLowerCase()
const client = serverSupabaseServiceRole(event)
// Check cache first
const { data: cached } = await client
.from('destination_images')
.select('*')
.eq('city_name', cityKey)
.single()
if (cached) {
// Refresh if older than 30 days
const age = Date.now() - new Date(cached.cached_at).getTime()
if (age < 30 * 24 * 60 * 60 * 1000) {
return cached
}
}
// Fetch from Unsplash
const accessKey = process.env.UNSPLASH_ACCESS_KEY
if (!accessKey) {
throw createError({ statusCode: 500, message: 'UNSPLASH_ACCESS_KEY not configured' })
}
const result = await $fetch<{ results: { urls: { regular: string; small: string }; user: { name: string; links: { html: string } } }[] }>('https://api.unsplash.com/search/photos', {
query: {
query: `${city} city travel`,
per_page: 1,
orientation: 'landscape',
},
headers: {
Authorization: `Client-ID ${accessKey}`,
},
}).catch(() => null)
if (!result?.results?.length) {
return null
}
const photo = result.results[0]
const row = {
city_name: cityKey,
image_url: photo.urls.regular,
thumb_url: photo.urls.small,
photographer: photo.user.name,
photographer_url: photo.user.links.html,
cached_at: new Date().toISOString(),
}
// Upsert cache
await client
.from('destination_images')
.upsert(row, { onConflict: 'city_name' })
return row
})