53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { sql } from "@/lib/db";
|
|
import { cacheGet, cacheSet } from "@/lib/cache";
|
|
import type { City } from "@transportationer/shared";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
export async function GET() {
|
|
const cacheKey = "api:cities:all";
|
|
const cached = await cacheGet<City[]>(cacheKey);
|
|
if (cached) {
|
|
return NextResponse.json(cached, { headers: { "X-Cache": "HIT" } });
|
|
}
|
|
|
|
const rows = await Promise.resolve(sql<{
|
|
slug: string;
|
|
name: string;
|
|
country_code: string;
|
|
geofabrik_url: string;
|
|
bbox_arr: number[] | null;
|
|
status: string;
|
|
last_ingested: string | null;
|
|
}[]>`
|
|
SELECT
|
|
slug,
|
|
name,
|
|
country_code,
|
|
geofabrik_url,
|
|
CASE WHEN bbox IS NOT NULL THEN ARRAY[
|
|
ST_XMin(bbox)::float,
|
|
ST_YMin(bbox)::float,
|
|
ST_XMax(bbox)::float,
|
|
ST_YMax(bbox)::float
|
|
] END AS bbox_arr,
|
|
status,
|
|
last_ingested
|
|
FROM cities
|
|
ORDER BY name
|
|
`);
|
|
|
|
const cities: City[] = rows.map((r) => ({
|
|
slug: r.slug,
|
|
name: r.name,
|
|
countryCode: r.country_code,
|
|
geofabrikUrl: r.geofabrik_url,
|
|
bbox: (r.bbox_arr as [number, number, number, number]) ?? [0, 0, 0, 0],
|
|
status: r.status as City["status"],
|
|
lastIngested: r.last_ingested,
|
|
}));
|
|
|
|
await cacheSet(cacheKey, cities, "API_CITIES");
|
|
return NextResponse.json(cities);
|
|
}
|