Support repeated stopIds and update WienerLinien API URL

This commit is contained in:
2026-05-10 18:06:41 +02:00
parent b2608a4a60
commit de9c16430b
6 changed files with 23 additions and 10 deletions
@@ -93,6 +93,16 @@ describe("GET /api/wienerlinien/monitor", () => {
expect(mockGetMonitor).toHaveBeenCalledWith(["1", "2", "3"]);
});
it("accepts repeated stopIds params from hook (stopIds=a&stopIds=b)", async () => {
mockGetMonitor.mockResolvedValue({ stops: [] });
const request = new NextRequest(
"http://localhost/api/wienerlinien/monitor?stopIds=WL:2000001&stopIds=WL:2000002&stopIds=WL:2000003",
);
await GET(request);
expect(mockGetMonitor).toHaveBeenCalledWith(["WL:2000001", "WL:2000002", "WL:2000003"]);
});
it("returns 500 with correlationId when client throws", async () => {
mockGetMonitor.mockRejectedValue(new Error("upstream timeout"));
+3 -4
View File
@@ -6,13 +6,12 @@ const client = new WienerLinienClient();
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const stopIdsParam = searchParams.get("stopIds");
if (!stopIdsParam || stopIdsParam.trim() === "") {
const stopIdsList = searchParams.getAll("stopIds");
if (stopIdsList.length === 0 || stopIdsList.every((v) => v.trim() === "")) {
return NextResponse.json({ error: "Missing 'stopIds' query parameter" }, { status: 400 });
}
const rawIds = stopIdsParam.split(",");
const rawIds = stopIdsList.flatMap((param) => param.split(","));
const validStopIds = rawIds
.map((id) => id.trim())
.filter((id) => id.length > 0)
+4 -1
View File
@@ -2,6 +2,7 @@
import { format } from "date-fns";
import { useJourneys } from "@/hooks/useJourneys";
import { useDestinationStation } from "@/hooks/useDestinationStation";
import { useBikeRoute } from "@/hooks/useBikeRoute";
import { useGeocode } from "@/hooks/useGeocode";
import { useClock } from "@/hooks/useClock";
@@ -18,11 +19,13 @@ interface EventCardProps {
}
export default function EventCard({ event, originStation }: EventCardProps) {
const destStation = useDestinationStation(event.destination);
const {
journeys,
loading: journeysLoading,
error: journeysError,
} = useJourneys(originStation?.extId ?? null, null, event.eventTime, 0);
} = useJourneys(originStation?.extId ?? null, destStation.station?.extId ?? null, event.eventTime, 0);
const destCoords = useGeocode(event.destination);
+3 -1
View File
@@ -7,6 +7,8 @@ interface HafasLocation {
type: string;
name: string;
extId: string;
lat: number;
lon: number;
}
export function useOriginStation() {
@@ -65,7 +67,7 @@ export function useOriginStation() {
const match = data?.svcResL?.[0]?.res?.match?.locL ?? [];
const stations: Station[] = (match as HafasLocation[])
.filter((l) => l.type === "S")
.map((l) => ({ name: l.name, extId: l.extId }));
.map((l) => ({ name: l.name, extId: l.extId, lat: l.lat, lng: l.lon }));
if (!isMounted) return;
@@ -291,7 +291,7 @@ describe("WienerLinienClient", () => {
new WienerLinienClient();
expect(ApiClient).toHaveBeenCalledWith({ baseUrl: "https://api.wienerlinien.at/darvin-v1" });
expect(ApiClient).toHaveBeenCalledWith({ baseUrl: "https://api.wienerlinien.at/darwin-v2" });
});
it("uses custom base URL when provided", () => {
+2 -3
View File
@@ -1,12 +1,11 @@
import { WIENER_LINIEN_API_URL } from "@/lib/constants";
import { ApiClient } from "@/lib/api-service";
import type { NearbyStop, WienerLinienDeparture, WienerLinienLine, WienerLinienMonitorResponse } from "@/types";
const DEFAULT_BASE_URL = "https://api.wienerlinien.at/darvin-v1";
export class WienerLinienClient {
private readonly client: ApiClient;
constructor(baseUrl: string = DEFAULT_BASE_URL) {
constructor(baseUrl: string = WIENER_LINIEN_API_URL) {
this.client = new ApiClient({ baseUrl });
}