Wegwichtel/docs/REST-API.md
2026-06-16 17:01:53 +02:00

17 KiB
Raw Blame History

Wegwichtel REST-API

Diese Datei dokumentiert die vollständige HTTP-Schnittstelle des aktuellen Wegwichtel-Servers. Die API wird unter /api bereitgestellt. Aktive GPX-, Bild- und Audiodateien werden zusätzlich unter /media ausgeliefert.

1. Grundlagen

Basisadresse

Lokaler Standard:

http://127.0.0.1:47145

API-Basis:

http://127.0.0.1:47145/api

Bei einer Nginx-Installation bleibt der Pfad gleich, beispielsweise:

https://wegwichtel.example.org/api

Formate

  • Lesezugriffe liefern JSON.
  • Routen- und POI-Schreibzugriffe mit Dateien verwenden multipart/form-data.
  • Fehler werden als JSON ausgegeben.
  • Zeitstempel stammen aus SQLite beziehungsweise JavaScript und werden als Text oder ISO-8601-Zeitstempel ausgegeben.
  • Die aktuelle API besitzt noch keine Authentifizierung. Schreibzugriffe dürfen deshalb nicht ungeschützt öffentlich erreichbar sein.

Allgemeines Fehlerformat

{
  "error": "HttpError",
  "message": "Strecke nicht gefunden."
}

Bei Detailinformationen kann zusätzlich details enthalten sein:

{
  "error": "HttpError",
  "message": "Die GPX-Datei ist kein gültiges XML.",
  "details": "Parsermeldung"
}

Typische Statuscodes:

Status Bedeutung
200 Anfrage erfolgreich
201 Ressource wurde angelegt
400 Parameter oder Upload unvollständig beziehungsweise ungültig
404 Route, POI oder Datei wurde nicht gefunden
409 Dateisystemzustand verhindert Löschen oder Wiederherstellen
413 Eine hochgeladene Datei überschreitet das konfigurierte Limit
415 Dateityp wird nicht unterstützt
500 Interner Serverfehler

IDs

Die Pfadparameter :id sind positive, von SQLite erzeugte Ganzzahlen. Beispiele verwenden überwiegend Route 1 und POI 7.

Uploadgrenzen und Dateitypen

Das Dateilimit pro Datei wird durch MAX_UPLOAD_MB festgelegt und beträgt standardmäßig 50 MB. Multer akzeptiert höchstens 25 Dateien pro Request.

Erlaubte Uploadtypen:

  • GPX/XML: .gpx, application/gpx+xml, application/xml, text/xml
  • Bilder: JPEG, PNG, WebP
  • Audio: MP3, MP4/M4A, AAC, Ogg, WAV, WebM

Beim Anlegen oder Aktualisieren eines POIs gelten zusätzlich:

  • höchstens eine Datei im Feld audio
  • höchstens 20 Dateien im Feld images

2. Datenmodelle

Kurzfassung einer Route

{
  "id": 1,
  "slug": "schulwald-runde",
  "name": "Schulwald-Runde",
  "description": "Naturkundlicher Rundweg",
  "schoolName": "Beispielschule",
  "status": "active",
  "start": { "lat": 52.5208, "lon": 13.4070 },
  "center": { "lat": 52.5210, "lon": 13.4080 },
  "bounds": {
    "minLat": 52.5208,
    "minLon": 13.4070,
    "maxLat": 52.5212,
    "maxLon": 13.4090
  },
  "distanceM": 842.6,
  "elevationGainM": 14.2,
  "pointCount": 87,
  "gpxUrl": "/media/routes/1/route.gpx",
  "createdAt": "2026-06-16 12:00:00",
  "updatedAt": "2026-06-16 12:00:00",
  "deletedAt": null,
  "proximityM": 324.8
}

proximityM ist null, wenn beim Listenaufruf keine gültige Position übergeben wurde. Bei gelöschten Routen ist gpxUrl null, weil Dateien im Papierkorb nicht öffentlich ausgeliefert werden.

Vollständige Route

GET /api/routes/:id ergänzt die Kurzfassung um points und pois:

{
  "id": 1,
  "name": "Schulwald-Runde",
  "points": [
    {
      "sequence": 0,
      "lat": 52.5208,
      "lon": 13.4070,
      "elevation": 71.4,
      "recordedAt": "2026-06-16T09:00:00Z"
    }
  ],
  "pois": []
}

POI

{
  "id": 7,
  "routeId": 1,
  "title": "Die alte Eiche",
  "description": "Hier wird das Alter der Eiche erklärt.",
  "lat": 52.5208,
  "lon": 13.4070,
  "triggerRadiusM": 60,
  "sequence": 2,
  "audioUrl": "/media/routes/1/audio/uuid.mp3",
  "images": [
    {
      "id": 15,
      "caption": "",
      "sequence": 0,
      "url": "/media/routes/1/images/uuid.jpg"
    }
  ]
}

3. Systemzustand

GET /api/health

Prüft den Node.js-Prozess und eine SQLite-Abfrage.

Parameter: keine.

curl http://127.0.0.1:47145/api/health

Beispielantwort:

{
  "ok": true,
  "service": "wegwichtel",
  "socket": "127.0.0.1:47145",
  "sqliteVersion": "3.46.1",
  "timestamp": "2026-06-16T12:00:00.000Z"
}

4. Routen lesen

GET /api/routes

Liefert standardmäßig alle aktiven Routen alphabetisch. Werden lat und lon gemeinsam übergeben, berechnet der Server die Entfernung zum Startpunkt, filtert anhand radiusKm und sortiert nach Entfernung.

Query-Parameter

Parameter Typ Pflicht Standard Beschreibung
lat Dezimalzahl nein Breitengrad der aktuellen Position; nur zusammen mit lon wirksam
lon Dezimalzahl nein Längengrad der aktuellen Position; nur zusammen mit lat wirksam
radiusKm Dezimalzahl nein DEFAULT_ROUTE_RADIUS_KM, standardmäßig 25 maximaler Abstand zum Routenstart; nur bei gültigem lat und lon wirksam
includeDeleted Boolean-Text nein false nur der exakte Wert true schließt gelöschte Routen ein

Alle aktiven Routen:

curl http://127.0.0.1:47145/api/routes

Alle Parameter in einem Beispiel:

curl --get http://127.0.0.1:47145/api/routes \
  --data-urlencode 'lat=52.5208' \
  --data-urlencode 'lon=13.4070' \
  --data-urlencode 'radiusKm=12.5' \
  --data-urlencode 'includeDeleted=true'

Antwort:

{
  "routes": [
    {
      "id": 1,
      "name": "Schulwald-Runde",
      "status": "active",
      "proximityM": 324.8
    }
  ]
}

Hinweise:

  • Eine ungültige Zahl wird intern wie ein nicht gesetzter Wert behandelt.
  • Der Positionsfilter wird nur aktiv, wenn sowohl lat als auch lon gültige Zahlen sind.
  • radiusKm wird derzeit nicht auf einen Mindest- oder Höchstwert begrenzt.

GET /api/routes/:id

Liefert eine Route mit sämtlichen GPX-Punkten und POIs.

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der Route

Query-Parameter

Parameter Typ Pflicht Standard Beschreibung
includeDeleted Boolean-Text nein false mit true kann auch eine als gelöscht markierte Route gelesen werden

Aktive Route:

curl http://127.0.0.1:47145/api/routes/1

Gelöschte Route ausdrücklich einschließen:

curl 'http://127.0.0.1:47145/api/routes/1?includeDeleted=true'

Bei einer gelöschten Route sind Medien-URLs null, weil der Papierkorb nicht unter /media veröffentlicht wird.

GET /api/routes/:id/pois

Liefert alle POIs einer aktiven Route in der Reihenfolge sequence, anschließend id.

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der aktiven Route

Weitere Parameter: keine.

curl http://127.0.0.1:47145/api/routes/1/pois

Antwort:

{
  "pois": [
    {
      "id": 7,
      "routeId": 1,
      "title": "Die alte Eiche",
      "sequence": 2,
      "audioUrl": "/media/routes/1/audio/uuid.mp3",
      "images": []
    }
  ]
}

5. POIs lesen

GET /api/pois/:id

Liefert einen einzelnen POI einschließlich Bild- und Audio-URLs. Der POI muss zu einer aktiven Route gehören.

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID des POIs

Weitere Parameter: keine.

curl http://127.0.0.1:47145/api/pois/7

6. Route anlegen

POST /api/routes

Legt eine neue Route aus einer GPX-Datei an. Trackpunkte, Streckenlänge, Höhengewinn, Startpunkt, Mittelpunkt und Grenzen werden aus der Datei berechnet.

Content-Type: multipart/form-data

Formular- und Dateiparameter

Feld Typ Pflicht Standard Beschreibung
gpx Datei ja GPX-Datei mit mindestens einem verwertbaren trkpt
name Text bedingt GPX-Track- oder Metadatenname Routenname; erforderlich, falls die GPX-Datei keinen Namen enthält
slug Text nein aus name abgeleitet URL-freundliche interne Kennung; Kollisionen erhalten automatisch -2, -3 usw.
description Text nein leer Beschreibung der Route
schoolName Text nein leer Name der Schule oder Einrichtung

Beispiel mit allen Parametern:

curl -X POST http://127.0.0.1:47145/api/routes \
  -F 'name=Schulwald-Runde' \
  -F 'slug=schulwald-runde-klasse-7a' \
  -F 'description=Naturkundlicher Rundweg der Klasse 7a' \
  -F 'schoolName=Beispielschule' \
  -F 'gpx=@examples/sample-route.gpx;type=application/gpx+xml'

Erfolg:

  • Status 201 Created
  • Header Location: /api/routes/<id>
  • Body: vollständige neu angelegte Route

7. Route vollständig aktualisieren

PUT /api/routes/:id

Ändert Metadaten einer aktiven Route. Eine optionale GPX-Datei ersetzt alle bisherigen Trackpunkte und die Datei route.gpx.

Content-Type: multipart/form-data

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der aktiven Route

Formular- und Dateiparameter

Feld Typ Pflicht Verhalten bei Auslassung Beschreibung
name Text nein alter Wert bleibt neuer Routenname
description Text nein alter Wert bleibt neue Beschreibung; leere Zeichenfolge löscht den Inhalt
schoolName Text nein alter Wert bleibt neuer Schulname; leere Zeichenfolge löscht den Inhalt
gpx Datei nein Track bleibt unverändert ersetzt GPX-Datei, Trackpunkte und berechnete Kennzahlen vollständig

slug kann über diesen Endpunkt derzeit nicht geändert werden.

Beispiel mit allen Parametern:

curl -X PUT http://127.0.0.1:47145/api/routes/1 \
  -F 'name=Schulwald-Runde  überarbeitet' \
  -F 'description=Neue Wegführung ab dem Schulhof' \
  -F 'schoolName=Beispielschule Nord' \
  -F 'gpx=@examples/sample-route.gpx;type=application/gpx+xml'

Nur die Beschreibung ändern:

curl -X PUT http://127.0.0.1:47145/api/routes/1 \
  -F 'description=Nur dieser Wert wird geändert.'

Antwort: vollständige aktualisierte Route.

8. GPX-Punkte an eine Route anhängen

POST /api/routes/:id/append

Hängt sämtliche verwertbaren Trackpunkte einer GPX-Datei an eine aktive Route an und berechnet die Streckenkennzahlen neu.

Content-Type: multipart/form-data

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der aktiven Route

Dateiparameter

Feld Typ Pflicht Beschreibung
gpx Datei ja GPX-Datei mit den anzuhängenden Trackpunkten
curl -X POST http://127.0.0.1:47145/api/routes/1/append \
  -F 'gpx=@weiterer-abschnitt.gpx;type=application/gpx+xml'

Hinweis: Die Punkte werden in SQLite ergänzt. Die gespeicherte Originaldatei route.gpx wird durch diesen Endpunkt derzeit nicht zu einer konsolidierten GPX-Datei erweitert.

9. POI anlegen

POST /api/routes/:id/pois

Legt einen POI für eine aktive Route an und speichert optional eine Audioansage und mehrere Bilder.

Content-Type: multipart/form-data

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der aktiven Route

Formular- und Dateiparameter

Feld Typ Pflicht Standard Beschreibung
title Text nein Unbenannter POI Titel der Station
description Text nein leer Beschreibung der Station
lat Dezimalzahl ja Breitengrad des POIs
lon Dezimalzahl ja Längengrad des POIs
triggerRadiusM Dezimalzahl nein DEFAULT_POI_TRIGGER_METERS, standardmäßig 80 Entfernung in Metern, ab der die Station automatisch ausgelöst wird
sequence Ganzzahl nein 0 Sortierreihenfolge innerhalb der Route
audio Datei nein keine eine Audioansage
images Datei, wiederholbar nein keine bis zu 20 Bilder; jedes Bild wird als eigenes Feld images gesendet

Beispiel mit allen Parametern:

curl -X POST http://127.0.0.1:47145/api/routes/1/pois \
  -F 'title=Die alte Eiche' \
  -F 'description=Hier wird das Alter der Eiche erklärt.' \
  -F 'lat=52.5208' \
  -F 'lon=13.4070' \
  -F 'triggerRadiusM=60' \
  -F 'sequence=2' \
  -F 'audio=@ansage.mp3;type=audio/mpeg' \
  -F 'images=@eiche-1.jpg;type=image/jpeg' \
  -F 'images=@eiche-2.webp;type=image/webp'

Erfolg:

  • Status 201 Created
  • Header Location: /api/pois/<id>
  • Body: neu angelegter POI

Bildunterschriften können in der aktuellen API noch nicht per Parameter gesetzt werden und bleiben leer.

10. POI aktualisieren und Medien ergänzen

PUT /api/pois/:id

Ändert einen POI einer aktiven Route. Eine neue Audiodatei ersetzt den in der Datenbank referenzierten Audiopfad. Neue Bilder werden an die vorhandene Bilderliste angehängt.

Content-Type: multipart/form-data

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID des POIs

Formular- und Dateiparameter

Feld Typ Pflicht Verhalten bei Auslassung Beschreibung
title Text nein alter Wert bleibt neuer Titel
description Text nein alter Wert bleibt neue Beschreibung
lat Dezimalzahl nein alter Wert bleibt neuer Breitengrad
lon Dezimalzahl nein alter Wert bleibt neuer Längengrad
triggerRadiusM Dezimalzahl nein alter Wert bleibt neuer automatischer Auslöseradius in Metern
sequence Ganzzahl nein alter Wert bleibt neue Sortierreihenfolge
audio Datei nein alte Referenz bleibt neue Audioansage; maximal eine Datei
images Datei, wiederholbar nein Bilder bleiben unverändert bis zu 20 zusätzliche Bilder

Beispiel mit allen Parametern:

curl -X PUT http://127.0.0.1:47145/api/pois/7 \
  -F 'title=Die sehr alte Eiche' \
  -F 'description=Überarbeitete Ansage und neue Fotos.' \
  -F 'lat=52.5209' \
  -F 'lon=13.4072' \
  -F 'triggerRadiusM=45' \
  -F 'sequence=3' \
  -F 'audio=@ansage-neu.ogg;type=audio/ogg' \
  -F 'images=@eiche-3.png;type=image/png' \
  -F 'images=@eiche-4.jpg;type=image/jpeg'

Wichtige aktuelle Einschränkungen:

  • Einzelne Bilder können noch nicht per API gelöscht, umsortiert oder beschriftet werden.
  • Neu hochgeladene Bilder werden hinter vorhandenen Bildern einsortiert.
  • Beim Ersetzen der Audio-Referenz wird die vorherige Audiodatei derzeit nicht automatisch aus dem aktiven Verzeichnis entfernt.

11. Route zum Löschen markieren

DELETE /api/routes/:id

Markiert eine aktive Route als gelöscht und verschiebt ihr gesamtes Verzeichnis einschließlich GPX, Bildern und Audio nach storage/trash/routes. Die Datenbankzeilen bleiben erhalten; alle gespeicherten Pfade werden auf den Papierkorb umgeschrieben.

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der aktiven Route

Weitere Parameter: keine.

curl -X DELETE http://127.0.0.1:47145/api/routes/1

Antwort:

{
  "route": {
    "id": 1,
    "status": "deleted",
    "gpxUrl": null,
    "deletedAt": "2026-06-16 12:30:00"
  },
  "softDeleted": true
}

Es werden keine Dateien endgültig entfernt.

12. Route wiederherstellen

POST /api/routes/:id/restore

Stellt eine als gelöscht markierte Route wieder her, verschiebt ihr Verzeichnis nach storage/active/routes/<id> zurück und korrigiert alle GPX-, Bild- und Audiopfade.

Pfadparameter

Parameter Typ Pflicht Beschreibung
id Ganzzahl ja ID der gelöschten Route

Weitere Parameter: keine. Der Request besitzt keinen Body.

curl -X POST http://127.0.0.1:47145/api/routes/1/restore

Antwort:

{
  "route": {
    "id": 1,
    "status": "active",
    "gpxUrl": "/media/routes/1/route.gpx",
    "deletedAt": null
  },
  "restored": true
}

13. Medien abrufen

Aktive Dateien werden nicht unter /api, sondern statisch unter /media ausgeliefert. Die benötigten URLs stehen in gpxUrl, audioUrl und images[].url.

Parameter: keine zusätzlichen Query- oder Formularparameter. Der komplette Pfad stammt aus der jeweiligen API-Antwort.

GPX-Datei:

curl --output route.gpx \
  http://127.0.0.1:47145/media/routes/1/route.gpx

Audio:

curl --output ansage.mp3 \
  http://127.0.0.1:47145/media/routes/1/audio/DATEINAME.mp3

Bild:

curl --output station.jpg \
  http://127.0.0.1:47145/media/routes/1/images/DATEINAME.jpg

Nur storage/active wird veröffentlicht. Dateien gelöschter Routen unter storage/trash sind nicht über HTTP erreichbar.

14. Endpunktübersicht

Methode Pfad Zweck
GET /api/health Server und SQLite prüfen
GET /api/routes Routen auflisten und optional räumlich filtern
GET /api/routes/:id vollständige Route lesen
GET /api/routes/:id/pois POIs einer Route lesen
GET /api/pois/:id einzelnen POI lesen
POST /api/routes Route aus GPX anlegen
PUT /api/routes/:id Route aktualisieren oder GPX ersetzen
POST /api/routes/:id/append GPX-Punkte anhängen
POST /api/routes/:id/pois POI und Medien anlegen
PUT /api/pois/:id POI aktualisieren und Medien ergänzen
DELETE /api/routes/:id Route in den Papierkorb verschieben
POST /api/routes/:id/restore Route wiederherstellen
GET /media/routes/... aktive GPX-, Bild- und Audiodateien abrufen