feat: add consent-based GPS location
This commit is contained in:
65
app/api/locations/reverse/route.ts
Normal file
65
app/api/locations/reverse/route.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const REVERSE_GEOCODING_URL = "https://nominatim.openstreetmap.org/reverse";
|
||||
const USER_AGENT = "wtr./1.0 (https://git.zvcloud.net/zv/wtr)";
|
||||
|
||||
interface RawReverseLocation {
|
||||
name?: string;
|
||||
display_name?: string;
|
||||
address?: {
|
||||
city?: string;
|
||||
town?: string;
|
||||
village?: string;
|
||||
municipality?: string;
|
||||
state?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function parseCoordinate(value: string | null, min: number, max: number) {
|
||||
if (!value?.trim()) return null;
|
||||
const coordinate = Number(value);
|
||||
return Number.isFinite(coordinate) && coordinate >= min && coordinate <= max ? Number(coordinate.toFixed(3)) : null;
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const latitude = parseCoordinate(searchParams.get("latitude"), -90, 90);
|
||||
const longitude = parseCoordinate(searchParams.get("longitude"), -180, 180);
|
||||
const language = searchParams.get("language") === "en" ? "en" : "pl";
|
||||
if (latitude === null || longitude === null) {
|
||||
return NextResponse.json({ error: "Invalid coordinates." }, { status: 400 });
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
format: "jsonv2",
|
||||
lat: String(latitude),
|
||||
lon: String(longitude),
|
||||
zoom: "10",
|
||||
addressdetails: "1",
|
||||
"accept-language": language,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch(`${REVERSE_GEOCODING_URL}?${params}`, {
|
||||
next: { revalidate: 86400 },
|
||||
headers: { Accept: "application/json", "User-Agent": USER_AGENT },
|
||||
});
|
||||
if (!response.ok) return NextResponse.json({ error: "Reverse geocoding is unavailable." }, { status: 502 });
|
||||
const data = await response.json() as RawReverseLocation;
|
||||
const name = data.address?.city
|
||||
?? data.address?.town
|
||||
?? data.address?.village
|
||||
?? data.address?.municipality
|
||||
?? data.name
|
||||
?? data.display_name?.split(",")[0]?.trim();
|
||||
if (!name) return NextResponse.json({ error: "Place name is unavailable." }, { status: 404 });
|
||||
return NextResponse.json({
|
||||
name,
|
||||
province: data.address?.state ?? null,
|
||||
}, {
|
||||
headers: { "Cache-Control": "public, s-maxage=86400, stale-while-revalidate=604800" },
|
||||
});
|
||||
} catch {
|
||||
return NextResponse.json({ error: "Reverse geocoding is unavailable." }, { status: 502 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user