Zum Hauptinhalt springen

Ressourcen erstellen & aktualisieren

Diese Seite beschreibt das Schreibmodell der REST-API: wie sich Erstellungen, partielle Aktualisierungen, vollständige Ersetzungen, das Leeren von Feldern und die Nebenläufigkeitskontrolle verhalten. Es ist der Kontrakt, dem jeder Schreib-Endpoint folgt.

:::note Ziel-Kontrakt Dies beschreibt den beabsichtigten Schreibkontrakt für /api/v2. Die meisten Ressourcen folgen ihm bereits; einige ältere Endpoints werden noch angeglichen. Wenn das Verhalten eines Endpoints von dem hier Beschriebenen abweicht, ist das hier Beschriebene die Zielrichtung — melden Sie es als Bug. :::

Ressourcen erstellen (POST)​

Erstellen Sie eine Ressource per POST an ihre Collection. Bei Erfolg liefert die API 201 Created mit der vollständigen erstellten Ressource im Body:

curl -X POST "https://api.tourfold.com/api/v2/areas" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Wien Nord",
"color": "#3366FF",
"description": "Gebiet von Alpine Facility Services nördlich der Donau"
}'
{
"id": "a1b2c3d4-e5f6-4a1b-8c9d-123456789abc",
"name": "Wien Nord",
"color": "#3366FF",
"description": "Gebiet von Alpine Facility Services nördlich der Donau",
"lock_version": 0
}

Jede 201 Created-Antwort enthält außerdem einen absoluten Location-Header mit der kanonischen URL der neu erstellten Ressource:

Location: https://api.tourfold.com/api/v2/areas/a1b2c3d4-e5f6-4a1b-8c9d-123456789abc

Bei einer Batch-Erstellung mehrerer Ressourcen verweist Location auf die Collection, da es keine einzelne kanonische Ressourcen-URL gibt.

Partielle Aktualisierungen (PATCH)​

Aktualisierungen erfolgen als PATCH mit partieller (Merge-)Semantik — Sie senden nur die Felder, die Sie ändern möchten. Dies folgt RFC 7386 JSON Merge Patch:

  • Ein aus dem Request-Body weggelassenes Feld bleibt unverändert.
  • Für leerbare optionale Felder leert ein explizites null den gespeicherten Wert (siehe unten).
  • Validierungs- und Eindeutigkeitsprüfungen laufen nur für die von Ihnen gesendeten Felder.

Senden Sie Content-Type: application/merge-patch+json. Derselbe Body wird auch als application/json akzeptiert (ein Alias mit identischer Weglassen/null-Semantik), damit generische HTTP-Clients weiter funktionieren.

# Das Gebiet umbenennen, Farbe und Beschreibung unberührt lassen
curl -X PATCH "https://api.tourfold.com/api/v2/areas/a1b2c3d4-e5f6-4a1b-8c9d-123456789abc" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-d '{ "name": "Wien Nord und Zentrum" }'

Ein optionales Feld leeren (null)​

Für Felder, die optional und leerbar sind, senden Sie ein explizites null, um den gespeicherten Wert zu entfernen. Das Weglassen des Felds lässt es unverändert; nur ein explizites null leert es.

# Die Beschreibung leeren, alles andere beibehalten
curl -X PATCH "https://api.tourfold.com/api/v2/areas/a1b2c3d4-e5f6-4a1b-8c9d-123456789abc" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/merge-patch+json" \
-d '{ "description": null }'

Felder, die erforderlich sind, können auf diese Weise nicht geleert werden. Das Senden von null für ein erforderliches Feld (oder für ein Feld, das für eine abhängige Operation erforderlich ist, etwa ein abrechnungsrelevantes Rechnungsfeld) liefert 422 Unprocessable Entity mit einem problem+json-Body, statt es stillschweigend zu ignorieren.

Vollständige Ersetzung (PUT)​

PUT wird nur dort verwendet, wo die deklarative Ersetzung einer ganzen Menge der Kontrakt ist — nicht als allgemeines Aktualisierungs-Verb. Wo ein PUT-Endpoint existiert, ersetzt er die gesamte Zielmenge: Der von Ihnen gesendete Body wird zum neuen Zustand, und alles, was im Body fehlt, wird entfernt. Ein leeres Array leert die Menge.

# Die Fähigkeiten eines Benutzers vollständig ersetzen — [] entfernt alle Fähigkeiten
curl -X PUT "https://api.tourfold.com/api/v2/users/{user_id}/skills" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"skill_ids": [
"00000000-0000-4000-8000-000000005101",
"00000000-0000-4000-8000-000000005102"
]
}'

Um Jonas' gesamte Fähigkeitsmenge zu leeren, ersetzen Sie sie durch eine leere Menge:

curl -X PUT "https://api.tourfold.com/api/v2/users/{user_id}/skills" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "skill_ids": [] }'

Wenn Sie ein einzelnes Attribut einer Ressource ändern möchten, verwenden Sie PATCH auf der Ressource. Greifen Sie nur dann zu PUT, wenn der Endpoint explizit eine Mengen-Ersetzung (z. B. Tags, Fähigkeiten) oder eine deklarative Schema-Ersetzung ist.

Unveränderliche Felder​

Einige Felder werden bei der Erstellung festgelegt und können bei einer Aktualisierung nicht geändert werden (zum Beispiel der type eines SMS-Gateways). Das Senden eines Werts, der dem gespeicherten widerspricht, wird mit 422 abgelehnt, statt stillschweigend ignoriert zu werden, damit Sie nie glauben, eine Änderung sei wirksam geworden, obwohl sie es nicht ist.

Optimistische Nebenläufigkeit (lock_version)​

Jede beschreibbare Ressource stellt eine lock_version-Ganzzahl bereit, die bei jedem erfolgreichen Schreibvorgang hochgezählt wird. Um verlorene Aktualisierungen zu verhindern, wenn mehrere Clients dieselbe Ressource bearbeiten, fügen Sie die zuletzt gelesene lock_version in Ihren Schreib-Body ein:

curl -X PATCH "https://api.tourfold.com/api/v2/areas/a1b2c3d4-e5f6-4a1b-8c9d-123456789abc" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Wien Nord und Zentrum", "lock_version": 3 }'
  • Wenn die übergebene lock_version mit der gespeicherten Version übereinstimmt, wird der Schreibvorgang ausgeführt und die Version erhöht.
  • Wenn sie nicht übereinstimmt (jemand hat zwischenzeitlich geschrieben), liefert die API 409 Conflict mit dem Problemtyp resource-conflict. Lesen Sie die Ressource erneut, führen Sie die Änderungen zusammen und versuchen Sie es erneut.
  • lock_version ist optional: Lassen Sie es weg (oder senden Sie null), um die Prüfung zu überspringen und ein Last-Write-Wins-Update durchzuführen.
  • Löschungen nehmen niemals eine lock_version entgegen. DELETE-Anfragen haben keinen Body; eine Löschung wird immer bedingungslos auf die aktuell gespeicherte Version angewendet.
  • Ausnahme — Workspace-Einstellungs-Singletons: einige kleine Konfigurations-Endpoints (/document-management/settings, /mcp/settings, /ai-assistant/settings und /geoservices/settings) haben keine lock_version und wenden immer Last-Write-Wins an. Jeder davon ist eine einzelne Zeile pro Workspace, die von einem Administrator über einen dedizierten Schalter bearbeitet wird — es gibt also kein Szenario konkurrierender verlorener Updates. /tenant und /billing/profile sind ebenfalls Singletons, haben aber sehr wohl eine lock_version, weil sie zusammengesetzte Datensätze sind, die von mehreren Admins bearbeitet werden.

Erfolgsstatus und Form der Antwort​

Erstellungs- und Aktualisierungs-Endpoints geben nach dem Schreibvorgang die vollständige Ressource zurück, sodass Sie den resultierenden Zustand (einschließlich der neuen lock_version) stets ohne ein nachfolgendes GET sehen. Eine synchrone Operation, die eine Repräsentation zurückgibt, verwendet 200 OK (beziehungsweise 201 Created bei einer Erstellung).

Eine Operation, die erfolgreich abgeschlossen wird und absichtlich keine Antwortrepräsentation besitzt, liefert 204 No Content mit leerem Body. Dies ist der übliche Kontrakt für Löschungen und bodylose Aktionen wie Zuordnungen aufheben, entfernen oder deaktivieren. Gibt eine Löschung dagegen bewusst die gelöschte Ressource oder ein aktualisiertes Aggregat zurück, verwendet sie 200 OK; 204 wird nicht mechanisch auf jedes DELETE angewendet.

Zur asynchronen Verarbeitung angenommene Arbeit verwendet 202 Accepted. Eingehende Webhook-Endpoints folgen dem Bestätigungs-Kontrakt des Absenders — üblicherweise einem ausdrücklichen 200 oder 202 — und werden nicht allein aus Gründen der Einheitlichkeit auf 204 geändert.

Antworten lassen Felder ohne Wert weg — ein soeben mit null geleertes Feld kommt also fehlend zurück, nicht als "field": null. Behandeln Sie einen fehlenden Schlüssel als „nicht gesetzt". Die vollständige Konvention finden Sie unter Grundlagen → Optionale Felder und null, die gemeinsamen JSON-Konventionen (snake_case-Schlüssel, RFC-3339-Zeitstempel, UUID-Bezeichner) unter Grundlagen und das problem+json-Fehlerformat unter Fehler.

Feldtyp-Konflikte​

Ein Anfragefeld, dessen Wert den falschen JSON-Typ oder die falsche Struktur hat — ein String, wo eine Zahl erwartet wird, 1.5 für ein Integer-Feld, ein Objekt, wo ein Array erwartet wird — wird mit 422 Unprocessable Content abgelehnt, Problemtyp field-type-invalid, samt einem errors[].pointer, der das betroffene Feld benennt (z. B. #/lock_version, #/tag_ids/0). Dies ist dieselbe errors[]-Struktur wie bei jeder anderen Feldvalidierung, sodass Sie die Meldung ohne Sonderbehandlung an das Eingabefeld binden können. Ein Body, der überhaupt kein gültiges JSON ist (ein Syntaxfehler, eine abgeschnittene Nutzlast), ergibt stattdessen 400 Bad Request.