feat: REST-API unter /api/v1 mit OpenAPI-Beschreibung

Dieselben Endpunkte bedienen Skripte und das eigene Frontend: erst wird ein
Bearer-Token geprüft, sonst das Sitzungscookie.

Sichtungsaktionen geben immer watchIds zurück — damit lässt sich genau diese
Aktion über DELETE zurücknehmen, ohne raten zu müssen, was dazugehörte.

Die OpenAPI-Beschreibung ist handgeschrieben statt aus Zod erzeugt: die
Schnittstelle ist überschaubar, und ein Generator brächte eine weitere
Abhängigkeit für einen Nutzen, den ein Dutzend Zeilen JSON auch hergeben.
This commit is contained in:
Florian Wilde
2026-09-01 20:24:48 +02:00
parent b25f0473fd
commit bb63827bf7
12 changed files with 847 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
import { NextResponse } from "next/server";
import { withApi } from "@/lib/api";
import { exportCsv, exportJson } from "@/lib/transfer";
/**
* GET /api/v1/export?format=json|csv
*
* Vollständiger Export der eigenen Daten. JSON enthält zusätzlich Sichtungen
* und Universen, CSV ist die schlanke Tabellenform für Tabellenkalkulationen.
*/
export const GET = withApi(async (request, user) => {
const url = new URL(request.url);
const format = url.searchParams.get("format") === "csv" ? "csv" : "json";
const stamp = new Date().toISOString().slice(0, 10);
if (format === "csv") {
const csv = await exportCsv(user.id);
return new NextResponse(csv, {
headers: {
"content-type": "text/csv; charset=utf-8",
"content-disposition": `attachment; filename="flimmer-${stamp}.csv"`,
},
});
}
const data = await exportJson(user.id);
return new NextResponse(JSON.stringify(data, null, 2), {
headers: {
"content-type": "application/json; charset=utf-8",
"content-disposition": `attachment; filename="flimmer-${stamp}.json"`,
},
});
});