fixed missing endpoint GET /routes/:id/pois/:id and added json style fileupload
This commit is contained in:
+172
-20
@@ -28,9 +28,13 @@ https://wegwichtel.example.org/api
|
||||
|
||||
- Listen- und Metadatenzugriffe liefern JSON.
|
||||
- Die Einzelendpunkte für GPX, Bilder und Audio liefern die jeweilige Datei direkt aus. Mit `?metadata=true` liefern die Bild- und Audioendpunkte stattdessen JSON-Metadaten.
|
||||
- Schreibzugriffe ohne Dateien akzeptieren JSON, `application/x-www-form-urlencoded` oder `multipart/form-data`.
|
||||
- Schreibzugriffe mit Dateien verwenden `multipart/form-data`.
|
||||
- Schreibzugriffe ohne Dateien akzeptieren `application/json`, `application/x-www-form-urlencoded` oder `multipart/form-data`.
|
||||
- GPX-Dateien werden weiterhin ausschließlich als `multipart/form-data` übertragen.
|
||||
- Bild- und Audioendpunkte akzeptieren wahlweise `multipart/form-data` oder ein JSON-Objekt mit Base64-kodierten Dateidaten.
|
||||
- Für JSON wird `Content-Type: application/json` empfohlen. `Content-Type: text/json` wird aus Kompatibilitätsgründen ebenfalls akzeptiert.
|
||||
- Ein leeres JSON-Objekt (`{}`) enthält keine Datei und kann deshalb keinen Bild- oder Audio-Upload ausführen.
|
||||
- Pro Medien-Request wird genau eine Bild- beziehungsweise Audiodatei verarbeitet.
|
||||
- Base64 vergrößert die Requestgröße um ungefähr ein Drittel und benötigt beim Verarbeiten zusätzlichen Arbeitsspeicher. Für große Dateien ist `multipart/form-data` vorzuziehen.
|
||||
- Zeitstempel werden als SQLite- oder ISO-8601-Text ausgegeben.
|
||||
- Die aktuelle API besitzt keine Authentifizierung. Schreibzugriffe dürfen nicht ungeschützt öffentlich erreichbar sein.
|
||||
|
||||
@@ -48,12 +52,23 @@ Unterstützte Dateitypen:
|
||||
|
||||
Die Uploadfelder heißen:
|
||||
|
||||
| Ressource | Feldname |
|
||||
| Ressource | Multipart-Feld beziehungsweise JSON-Eigenschaft |
|
||||
|---|---|
|
||||
| GPX | `gpx` |
|
||||
| einzelnes Bild | `picture` |
|
||||
| einzelne Audiodatei | `audio` |
|
||||
|
||||
Bei einem JSON-Medienupload ist `picture` beziehungsweise `audio` ein Objekt:
|
||||
|
||||
| Eigenschaft | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
| `filename` | Text | ja | ursprünglicher Dateiname einschließlich passender Endung |
|
||||
| `contentType` | Text | ja, sofern keine `dataUrl` den Typ enthält | MIME-Typ, beispielsweise `image/jpeg` oder `audio/mpeg` |
|
||||
| `base64` | Text | ja, sofern `dataUrl` fehlt | reiner Base64-Inhalt ohne Präfix |
|
||||
| `dataUrl` | Text | alternativ zu `base64` | vollständige Base64-Data-URL, beispielsweise `data:image/png;base64,...` |
|
||||
|
||||
`base64` und `dataUrl` sind Alternativen. Wird `dataUrl` verwendet, kann `contentType` daraus übernommen werden. `filename` bleibt erforderlich, weil die Dateiendung für Ablage und Auslieferung benötigt wird.
|
||||
|
||||
### Fehlerformat
|
||||
|
||||
```json
|
||||
@@ -184,9 +199,9 @@ Pro POI kann höchstens eine Audiodatei existieren. Deshalb wird die Audioressou
|
||||
| `DELETE` | `/api/routes/:id` | Route weich löschen |
|
||||
| `POST` | `/api/routes/:id/restore` | Route wiederherstellen |
|
||||
| `GET` | `/api/routes/:id/pois` | POIs einer Route auflisten |
|
||||
| `GET` | `/api/pois/:id` | einzelnen POI lesen |
|
||||
| `GET` | `/api/routes/:routeId/pois/:poiId` | einzelnen POI der Route lesen |
|
||||
| `POST` | `/api/routes/:id/pois` | POI-Metadaten anlegen |
|
||||
| `PUT` | `/api/pois/:id` | POI-Metadaten aktualisieren |
|
||||
| `PUT` | `/api/routes/:routeId/pois/:poiId` | POI-Metadaten aktualisieren |
|
||||
| `GET` | `/api/routes/:routeId/pois/:poiId/pictures` | Bilder eines POIs auflisten |
|
||||
| `GET` | `/api/routes/:routeId/pois/:poiId/pictures/:pictureId` | Bilddatei ausliefern; optional Metadaten mit `?metadata=true` |
|
||||
| `POST` | `/api/routes/:routeId/pois/:poiId/pictures` | einzelnes Bild für den POI hochladen |
|
||||
@@ -352,14 +367,21 @@ Liefert alle POIs einer aktiven Route nach `sequence` und `id`.
|
||||
curl http://127.0.0.1:47145/api/routes/1/pois
|
||||
```
|
||||
|
||||
### `GET /api/pois/:id`
|
||||
### `GET /api/routes/:routeId/pois/:poiId`
|
||||
|
||||
Liefert einen einzelnen POI einschließlich seiner aktuellen Bild- und Audio-URLs.
|
||||
Liefert einen einzelnen POI einschließlich seiner aktuellen Bild- und Audio-URLs. Route und POI werden gemeinsam geprüft; der POI muss zur angegebenen aktiven Route gehören.
|
||||
|
||||
| Pfadparameter | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
| `routeId` | Ganzzahl | ja | ID der aktiven Route |
|
||||
| `poiId` | Ganzzahl | ja | ID des POIs innerhalb dieser Route |
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:47145/api/pois/7
|
||||
curl http://127.0.0.1:47145/api/routes/1/pois/7
|
||||
```
|
||||
|
||||
Eine unbekannte Route, ein unbekannter POI oder eine falsche Route-POI-Kombination liefert `404 Not Found`.
|
||||
|
||||
### `POST /api/routes/:id/pois`
|
||||
|
||||
Legt ausschließlich die POI-Metadaten an. Bilder und Audio werden anschließend über die gesonderten Medienendpunkte hochgeladen.
|
||||
@@ -388,11 +410,16 @@ curl -X POST http://127.0.0.1:47145/api/routes/1/pois \
|
||||
}'
|
||||
```
|
||||
|
||||
Erfolg: `201 Created` und `Location: /api/pois/<id>`.
|
||||
Erfolg: `201 Created` und `Location: /api/routes/<routeId>/pois/<poiId>`.
|
||||
|
||||
### `PUT /api/pois/:id`
|
||||
### `PUT /api/routes/:routeId/pois/:poiId`
|
||||
|
||||
Aktualisiert ausschließlich POI-Metadaten. Nicht übergebene Werte bleiben erhalten.
|
||||
Aktualisiert ausschließlich POI-Metadaten. Nicht übergebene Werte bleiben erhalten. Route und POI werden gemeinsam validiert; ein POI kann über diesen Endpunkt keiner anderen Route zugeordnet werden.
|
||||
|
||||
| Pfadparameter | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
| `routeId` | Ganzzahl | ja | ID der aktiven Route |
|
||||
| `poiId` | Ganzzahl | ja | ID des POIs innerhalb dieser Route |
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
@@ -404,7 +431,7 @@ Aktualisiert ausschließlich POI-Metadaten. Nicht übergebene Werte bleiben erha
|
||||
| `sequence` | nichtnegative Ganzzahl | nein | neue Reihenfolge |
|
||||
|
||||
```bash
|
||||
curl -X PUT http://127.0.0.1:47145/api/pois/7 \
|
||||
curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7 \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"title": "Die sehr alte Eiche",
|
||||
@@ -479,9 +506,9 @@ Die API antwortet mit `404`, wenn Route, POI oder Bild nicht zusammengehören.
|
||||
|
||||
### `POST /api/routes/:routeId/pois/:poiId/pictures`
|
||||
|
||||
Lädt genau ein Bild für den im Pfad angegebenen POI hoch.
|
||||
Lädt genau ein Bild für den im Pfad angegebenen POI hoch. Zulässig sind zwei Übertragungsformen.
|
||||
|
||||
Content-Type: `multipart/form-data`
|
||||
#### Variante A: `multipart/form-data`
|
||||
|
||||
| Feld | Typ | Pflicht | Standard | Beschreibung |
|
||||
|---|---|---:|---:|---|
|
||||
@@ -496,6 +523,60 @@ curl -X POST http://127.0.0.1:47145/api/routes/1/pois/7/pictures \
|
||||
-F 'picture=@eiche.jpg;type=image/jpeg'
|
||||
```
|
||||
|
||||
#### Variante B: JSON mit Base64
|
||||
|
||||
Empfohlener Content-Type: `application/json`. Der Server akzeptiert zusätzlich `text/json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"caption": "Blick auf die Baumkrone",
|
||||
"sequence": 0,
|
||||
"picture": {
|
||||
"filename": "eiche.jpg",
|
||||
"contentType": "image/jpeg",
|
||||
"base64": "/9j/4AAQSkZJRgABAQ..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Beispiel mit `text/json` und einer separat erzeugten Payload-Datei:
|
||||
|
||||
```bash
|
||||
base64 < eiche.jpg | tr -d '\n' > eiche.jpg.b64
|
||||
|
||||
jq -n \
|
||||
--arg caption 'Blick auf die Baumkrone' \
|
||||
--argjson sequence 0 \
|
||||
--rawfile data eiche.jpg.b64 \
|
||||
'{
|
||||
caption: $caption,
|
||||
sequence: $sequence,
|
||||
picture: {
|
||||
filename: "eiche.jpg",
|
||||
contentType: "image/jpeg",
|
||||
base64: $data
|
||||
}
|
||||
}' > picture.json
|
||||
|
||||
curl -X POST http://127.0.0.1:47145/api/routes/1/pois/7/pictures \
|
||||
-H 'Content-Type: text/json' \
|
||||
--data-binary @picture.json
|
||||
```
|
||||
|
||||
Alternativ kann eine Data-URL übertragen werden:
|
||||
|
||||
```json
|
||||
{
|
||||
"caption": "Blick auf die Baumkrone",
|
||||
"picture": {
|
||||
"filename": "eiche.png",
|
||||
"dataUrl": "data:image/png;base64,iVBORw0KGgoAAA..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ein Request mit `-d '{}'` schlägt mit `400 Bad Request` fehl, weil weder eine Multipart-Datei noch ein JSON-Dateiobjekt enthalten ist.
|
||||
|
||||
Erfolg: `201 Created` und `Location: /api/routes/1/pois/7/pictures/<pictureId>`.
|
||||
|
||||
### `PUT /api/routes/:routeId/pois/:poiId/pictures/:pictureId`
|
||||
@@ -504,7 +585,7 @@ Aktualisiert Metadaten und kann optional die Datei ersetzen. Nicht übergebene M
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
| `picture` | Datei | nein | ersetzt die bisherige Bilddatei |
|
||||
| `picture` | Multipart-Datei oder JSON-Dateiobjekt | nein | ersetzt die bisherige Bilddatei |
|
||||
| `caption` | Text | nein | neue Bildbeschreibung; leerer Text entfernt die Beschreibung |
|
||||
| `sequence` | nichtnegative Ganzzahl | nein | neue Position in der Diashow |
|
||||
|
||||
@@ -519,7 +600,7 @@ curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/pictures/15 \
|
||||
}'
|
||||
```
|
||||
|
||||
Datei und Metadaten ersetzen:
|
||||
Datei und Metadaten per Multipart ersetzen:
|
||||
|
||||
```bash
|
||||
curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/pictures/15 \
|
||||
@@ -528,6 +609,26 @@ curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/pictures/15 \
|
||||
-F 'picture=@eiche-neu.webp;type=image/webp'
|
||||
```
|
||||
|
||||
Datei und Metadaten per JSON ersetzen:
|
||||
|
||||
```json
|
||||
{
|
||||
"caption": "Neue Aufnahme der Eiche",
|
||||
"sequence": 2,
|
||||
"picture": {
|
||||
"filename": "eiche-neu.webp",
|
||||
"contentType": "image/webp",
|
||||
"base64": "UklGRiQAAABXRUJQVlA4..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/pictures/15 \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-binary @picture-update.json
|
||||
```
|
||||
|
||||
Wird eine Datei ersetzt, entfernt der Server die bisherige Datei nach erfolgreicher Datenbankaktualisierung.
|
||||
|
||||
### `DELETE /api/routes/:routeId/pois/:poiId/pictures/:pictureId`
|
||||
@@ -584,9 +685,9 @@ Antwortet mit `404`, wenn Route und POI nicht zusammengehören oder der POI kein
|
||||
|
||||
### `POST /api/routes/:routeId/pois/:poiId/audio`
|
||||
|
||||
Legt die Audiodatei des im Pfad angegebenen POIs an.
|
||||
Legt die Audiodatei des im Pfad angegebenen POIs an. Zulässig sind `multipart/form-data` und JSON mit Base64.
|
||||
|
||||
Content-Type: `multipart/form-data`
|
||||
#### Variante A: `multipart/form-data`
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
@@ -597,23 +698,74 @@ curl -X POST http://127.0.0.1:47145/api/routes/1/pois/7/audio \
|
||||
-F 'audio=@ansage.mp3;type=audio/mpeg'
|
||||
```
|
||||
|
||||
#### Variante B: JSON mit Base64
|
||||
|
||||
```json
|
||||
{
|
||||
"audio": {
|
||||
"filename": "ansage.mp3",
|
||||
"contentType": "audio/mpeg",
|
||||
"base64": "SUQzBAAAAAAAI1RTU0UAAA..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
base64 < ansage.mp3 | tr -d '\n' > ansage.mp3.b64
|
||||
|
||||
jq -n --rawfile data ansage.mp3.b64 \
|
||||
'{
|
||||
audio: {
|
||||
filename: "ansage.mp3",
|
||||
contentType: "audio/mpeg",
|
||||
base64: $data
|
||||
}
|
||||
}' > audio.json
|
||||
|
||||
curl -X POST http://127.0.0.1:47145/api/routes/1/pois/7/audio \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-binary @audio.json
|
||||
```
|
||||
|
||||
Auch hier wird `Content-Type: text/json` akzeptiert. Ein leeres `{}` enthält keine Audiodatei und liefert `400 Bad Request`.
|
||||
|
||||
Erfolg: `201 Created` und `Location: /api/routes/1/pois/7/audio`.
|
||||
|
||||
Existiert bereits eine Audiodatei, antwortet der Server mit `409`. Zum Ersetzen ist `PUT` zu verwenden.
|
||||
|
||||
### `PUT /api/routes/:routeId/pois/:poiId/audio`
|
||||
|
||||
Ersetzt die vorhandene Audiodatei des POIs.
|
||||
Ersetzt die vorhandene Audiodatei des POIs. Die Datei kann als Multipart-Upload oder als JSON-Dateiobjekt übertragen werden.
|
||||
|
||||
| Feld | Typ | Pflicht | Beschreibung |
|
||||
|---|---|---:|---|
|
||||
| `audio` | Datei | ja | neue Audiodatei |
|
||||
| `audio` | Multipart-Datei oder JSON-Dateiobjekt | ja | neue Audiodatei |
|
||||
|
||||
Multipart-Beispiel:
|
||||
|
||||
```bash
|
||||
curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/audio \
|
||||
-F 'audio=@ansage-neu.ogg;type=audio/ogg'
|
||||
```
|
||||
|
||||
JSON-Beispiel:
|
||||
|
||||
```json
|
||||
{
|
||||
"audio": {
|
||||
"filename": "ansage-neu.ogg",
|
||||
"contentType": "audio/ogg",
|
||||
"base64": "T2dnUwACAAAAAAAAAAB..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X PUT http://127.0.0.1:47145/api/routes/1/pois/7/audio \
|
||||
-H 'Content-Type: text/json' \
|
||||
--data-binary @audio-update.json
|
||||
```
|
||||
|
||||
Der Server entfernt die bisherige Datei nach erfolgreicher Aktualisierung. Besitzt der POI noch keine Audiodatei, antwortet der Server mit `404`; zum erstmaligen Anlegen ist `POST` zu verwenden.
|
||||
|
||||
### `DELETE /api/routes/:routeId/pois/:poiId/audio`
|
||||
|
||||
Reference in New Issue
Block a user