Files
wtr/app/api/locations/search/route.ts
zv 2182297adc
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
feat: add global weather support
2026-06-14 15:59:14 +02:00

57 lines
2.1 KiB
TypeScript

import { NextResponse } from "next/server";
import { getWeatherRegionForCountryCode } from "@/types/weather-region";
const GEOCODING_URL = "https://geocoding-api.open-meteo.com/v1/search";
interface RawLocation {
id?: number;
name?: string;
latitude?: number;
longitude?: number;
country?: string;
country_code?: string;
admin1?: string;
admin2?: string;
timezone?: string;
}
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const query = searchParams.get("query")?.trim() ?? "";
const language = searchParams.get("language") === "en" ? "en" : "pl";
if (query.length < 2 || query.length > 80) return NextResponse.json([]);
const params = new URLSearchParams({
name: query,
count: "10",
language,
format: "json",
});
try {
const response = await fetch(`${GEOCODING_URL}?${params}`, { next: { revalidate: 86400 } });
if (!response.ok) return NextResponse.json({ error: "Location search is unavailable." }, { status: 502 });
const data = await response.json() as { results?: RawLocation[] };
const results = (data.results ?? []).flatMap((location) => {
if (!location.id || !location.name || !Number.isFinite(location.latitude) || !Number.isFinite(location.longitude)) return [];
const countryCode = location.country_code?.toUpperCase() ?? null;
return [{
id: location.id,
name: location.name,
latitude: location.latitude as number,
longitude: location.longitude as number,
province: location.admin1 ?? null,
district: location.admin2 ?? null,
country: location.country ?? null,
countryCode,
admin1: location.admin1 ?? null,
admin2: location.admin2 ?? null,
timezone: location.timezone ?? null,
region: getWeatherRegionForCountryCode(countryCode),
}];
});
return NextResponse.json(results, { headers: { "Cache-Control": "public, s-maxage=86400, stale-while-revalidate=604800" } });
} catch {
return NextResponse.json({ error: "Location search is unavailable." }, { status: 502 });
}
}