OBS/Kostenpflichtige Module/RESTServer/Endpunkte: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| (2 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 153: | Zeile 153: | ||
| '''403''' || Zugang fehlt in der Berechtigungsliste | | '''403''' || Zugang fehlt in der Berechtigungsliste | ||
|- | |- | ||
| '''401''' || API-Key ungültig/fehlend | | '''401''' || API-Key ungültig/fehlend, JWT abgelaufen oder Sitzung gesperrt (''AUTH_EXPIRED'') | ||
|- | |- | ||
| '''500''' || Skript- oder Syntax-Fehler (Details in <code>RESTSRV_PROTO</code>) | | '''500''' || Skript- oder Syntax-Fehler (Details in <code>RESTSRV_PROTO</code>) | ||
| Zeile 161: | Zeile 161: | ||
| '''413''' || Hochgeladene Datei überschreitet die zulässige Maximalgrösse (<code>re_upload_size</code>) | | '''413''' || Hochgeladene Datei überschreitet die zulässige Maximalgrösse (<code>re_upload_size</code>) | ||
|- | |- | ||
| '''429''' || Rate-Limit | | '''429''' || Rate-Limit überschritten; die Antwort enthält den Header <code>Retry-After</code> | ||
|- | |||
| '''503''' || Eine Anfrage mit demselben <code>Idempotency-Key</code> wird gerade verarbeitet; die Antwort enthält <code>Retry-After</code> | |||
|- | |||
| '''409''' || Ein früherer Aufruf mit demselben <code>Idempotency-Key</code> ist ohne Ergebnis geblieben (<code>IDEMPOTENCY_UNRESOLVED</code>) | |||
|- | |||
| '''422''' || Derselbe <code>Idempotency-Key</code> wurde mit '''anderem''' Inhalt gesendet (<code>IDEMPOTENCY_KEY_REUSED</code>) | |||
|- | |||
| '''400''' || Die Anfrage wurde unverschlüsselt an einen TLS-Port geschickt (<code>http</code> statt <code>https</code>). Die Abweisung erfolgt vor Authentifizierung und Endpunkt-Skript | |||
|} | |} | ||
Jede Fehlerantwort besteht aus einem <code>error</code>-Objekt mit | |||
maschinenlesbarem Code - Aufbau siehe | |||
[[OBS/Kostenpflichtige Module/RESTServer|Übersicht]]. | |||
Daneben kann ein Endpunkt-Skript den Statuscode selbst setzen (z.B. <code>201</code>, <code>204</code>, <code>409</code>, <code>422</code>) sowie Response-Header wie <code>ETag</code> oder <code>Location</code> - siehe [[OBS/Kostenpflichtige Module/RESTServer/Scripting|Scripting]]. | Daneben kann ein Endpunkt-Skript den Statuscode selbst setzen (z.B. <code>201</code>, <code>204</code>, <code>409</code>, <code>422</code>) sowie Response-Header wie <code>ETag</code> oder <code>Location</code> - siehe [[OBS/Kostenpflichtige Module/RESTServer/Scripting|Scripting]]. | ||
== Idempotenz == | |||
Schickt ein Konsument bei <code>POST</code>, <code>PUT</code>, <code>PATCH</code> | |||
oder <code>DELETE</code> den Header <code>Idempotency-Key</code>, sorgt der Server | |||
selbst dafür, dass eine wiederholte Sendung '''keine Zweitwirkung''' hat. Das gilt | |||
für '''jeden''' Endpunkt - es muss weder am Endpunkt etwas eingestellt noch im | |||
Skript etwas programmiert werden. | |||
{| class="wikitable" | |||
! Situation !! Antwort des Servers | |||
|- | |||
| Erster Aufruf || Endpunkt läuft normal, das Ergebnis wird zum Schlüssel gespeichert | |||
|- | |||
| Wiederholung, gleicher Inhalt || '''Gespeicherte Antwort''' (gleicher Statuscode, gleicher Body, gleiche Header) plus Header <code>Idempotent-Replay: true</code>. Das Skript läuft '''nicht''' | |||
|- | |||
| Wiederholung, anderer Inhalt || '''422''' <code>IDEMPOTENCY_KEY_REUSED</code> - derselbe Schlüssel für einen anderen Inhalt ist ein Client-Fehler | |||
|- | |||
| Erster Aufruf läuft noch || '''503''' <code>IDEMPOTENCY_IN_PROGRESS</code> mit <code>Retry-After</code>. Beim nächsten Versuch liegt die gespeicherte Antwort vor | |||
|- | |||
| Früherer Aufruf ohne Ergebnis || '''409''' <code>IDEMPOTENCY_UNRESOLVED</code>. Der Dienst wurde zwischen Verarbeitung und Festschreiben unterbrochen; ob die Buchung stattgefunden hat, ist unbekannt und von Hand zu klären | |||
|} | |||
Wichtig für die Auslegung eines Endpunkts: | |||
* Antwortet das Skript mit '''2xx''', wird die Antwort gespeichert und bei einer Wiederholung erneut ausgeliefert. | |||
* Antwortet das Skript mit '''4xx''' (fachliche Ablehnung), wird der Schlüssel wieder '''freigegeben''' - der Konsument darf ihn nach Korrektur erneut verwenden. Sonst würde ein einziger Validierungsfehler den Schlüssel dauerhaft blockieren. | |||
* Endet die Verarbeitung mit '''5xx''' oder einem Skript-Fehler, bleibt der Schlüssel belegt und der Fall wird protokolliert. Das ist Absicht: lieber ein Fall für den Support als eine mögliche Doppelbuchung. | |||
Der Schlüssel gilt je '''Zugang, Methode und Pfad'''. Derselbe | |||
<code>Idempotency-Key</code> an einem anderen Endpunkt ist damit ein eigener | |||
Vorgang - der Konsument muss ihn nicht global eindeutig vergeben, aber pro Vorgang | |||
'''stabil wiederverwenden''' (also nicht bei jedem Wiederholversuch neu erzeugen). | |||
Die Einträge stehen in <code>RESTSRV_IDEMPOTENCY</code> und werden nach 30 Tagen | |||
automatisch aufgeräumt. Einträge ohne Ergebnis werden '''nicht''' automatisch | |||
gelöscht, sondern im Protokoll gemeldet. | |||
== WebHooks == | == WebHooks == | ||
| Zeile 171: | Zeile 220: | ||
erfolgreichen Aufruf wird die Antwort in der Tabelle <code>REMOTE_HOOK_URL</code> | erfolgreichen Aufruf wird die Antwort in der Tabelle <code>REMOTE_HOOK_URL</code> | ||
gespeichert und der Endpunkt anschließend automatisch gelöscht. | gespeichert und der Endpunkt anschließend automatisch gelöscht. | ||
Typischer Einsatz: OBS stösst einen Vorgang bei einem Fremdsystem an (Bezahldienst, | |||
Versanddienstleister) und gibt diesem eine Rückruf-Adresse mit, die nur '''ein | |||
einziges Mal''' gültig ist. Damit kann die Adresse nicht später erneut - oder von | |||
jemand anderem - benutzt werden. | |||
Ablauf: | |||
# OBS legt einen Eintrag in <code>REMOTE_HOOK_URL</code> an und dazu einen Endpunkt, dessen Feld '''WebHook''' (<code>re_webhook</code>) auf diesen Eintrag zeigt. Ein Skript wird für diesen Endpunkt nicht gepflegt. | |||
# Die Adresse dieses Endpunkts wird dem Fremdsystem als Callback-URL übergeben. | |||
# Das Fremdsystem ruft die Adresse auf. Der Server legt den übergebenen Inhalt in <code>REMOTE_HOOK_URL.hu_response</code> ab, antwortet mit <code>{"status": "ok"}</code> und '''löscht den Endpunkt'''. | |||
# Der weiterverarbeitende OBS-Prozess findet die Rückmeldung in <code>hu_response</code>. | |||
{{Hinweis|Ein zweiter Aufruf derselben Adresse läuft ins Leere: Der Endpunkt | |||
existiert nicht mehr, die Antwort ist 404. Das ist gewollt - ein WebHook ist keine | |||
dauerhafte Schnittstelle. Für eine dauerhaft erreichbare Rückmelde-Adresse einen | |||
normalen Endpunkt mit Skript anlegen.}} | |||
Aktuelle Version vom 19. August 2026, 11:15 Uhr
- A Preise aktualisieren
- C Personen übertragen
- E Kategorien verwalten
- G Kataloge verwalten
- I Merkliste übertragen
- K Varianten übertragen
- L Artikelvarianten übertragen
- M Referenzarten übertragen
- N Lagerbestände verwalten
- U Bestellungen einlesen
- V leere Passworte füllen
- W Update-Informationen zurücksetzen
- X Konfiguration
- Z Protokoll
Endpunkte
Ein Endpunkt stellt eine Adresse bereit, über die der REST-Server konkrete Funktionen anbietet. Jeder Endpunkt wird durch ein OBS-Skript oder einen WebHook realisiert und ist genau einem Server-Profil zugeordnet.
Routing über Pfad-Templates
Das Routing erfolgt über die Spalte Pfad-Template (re_pathtemplate).
Ein Template beschreibt den vollständigen Pfad nach dem Host und kann
Platzhalter enthalten:
- Statische Segmente müssen exakt übereinstimmen (Groß-/Kleinschreibung wird ignoriert).
- Platzhalter in geschweiften Klammern – z. B.
{uid}– passen auf einen beliebigen Wert und werden als Pfad-Parameter erfasst.
Beispiele für gültige Templates:
| Template | Passt auf | Pfad-Parameter |
|---|---|---|
/orders |
/orders |
– |
/orders/{uid} |
/orders/4711 |
uid = 4711
|
/orders/{uid}/modules/{code} |
/orders/4711/modules/A1 |
uid = 4711, code = A1
|
/kalender/v1 |
/kalender/v1 |
– |
Präzedenz bei mehreren Treffern
Passen mehrere Templates auf denselben Pfad, gewinnt das spezifischste –
also das mit den meisten statischen Segmenten. So schlägt /orders/summary
das Template /orders/{uid}, während /orders/4711 auf
/orders/{uid} matcht.
Hauptfelder eines Endpunkts
| Feld | Spalte | Zweck |
|---|---|---|
| Pfad-Template | re_pathtemplate |
Maßgeblich fürs Routing. Vollständiger Pfad mit Platzhaltern, z. B. /orders/{uid}/modules/{code}
|
| Server | re_server |
Zuordnung zum Server-Profil (erforderlich) |
| Aktiv | re_aktiv |
Statusflag; inaktive Endpunkte liefern 404 |
| Skript | re_script |
DwScript-Quelltext des Handlers (siehe Scripting) |
| WebHook | re_webhook |
optional: Verweis auf einen Einmal-Endpunkt statt Skript |
| Info | – | Dokumentations-Freitext |
| Datei-Upload | re_upload |
Erlaubt Datei-Uploads an diesem Endpunkt (0 = aus, 1 = an). Ohne Freigabe werden Upload-Anfragen mit 415 abgelehnt.
|
| Max. Upload-Grösse | re_upload_size |
Maximale Dateigrösse in MB. Leer/0 = Standard 25 MB. Überschreitung wird mit 413 abgelehnt. |
Pfad-Parameter im Skript
Die aus den Platzhaltern erfassten Werte stehen im Endpunkt-Skript als
reservierte Parameter mit Präfix _OBS_PATH_ zur Verfügung:
function Get(oParams: TStrings; oBody: TJSONObject): string;
var cUid: string;
begin
cUid := oParams.Values['_OBS_PATH_uid']; // aus /orders/{uid}
// ...
end;Da der Präfix _OBS_ für von außen gelieferte Header/Query-Parameter
gesperrt ist, können diese Werte nicht durch den Client überschrieben werden.
Datei-Uploads
Ein Endpunkt nimmt Datei-Uploads nur entgegen, wenn er dafür freigeschaltet ist
(re_upload = 1). Andernfalls werden Upload-Anfragen mit
415 Unsupported Media Type abgelehnt und das Skript wird nicht ausgeführt.
Die maximal zulässige Dateigrösse wird pro Endpunkt über re_upload_size
(in MB) festgelegt; ohne Angabe gilt der Standard von 25 MB. Wird das
Limit überschritten, antwortet der Server mit 413 Payload Too Large. Für
Uploads gilt nicht das JSON-Body-Limit (10 MB), sondern dieses Endpunkt-Limit.
Der Originalname (beim resumable Upload über den Header Upload-Metadata) ist Pflicht; fehlt er, wird der Upload mit 413/400 abgelehnt. Dem Skript stehen Pfad, Name und Content-Type als _OBS_UPLOAD_*-Parameter zur Verfügung (Details: Scripting).
Unterstützt werden zwei Übertragungsarten:
- Einfacher Upload per
multipart/form-data(eine Datei pro Request). - Resumable/Chunked Upload per
Content-Range(grosse Dateien, fortsetzbar nach Abbruch).
Der Server legt die hochgeladene Datei in einem temporären Verzeichnis ab und übergibt dem Endpunkt-Skript den Pfad. Was mit der Datei geschieht (Ablage, DMS-Verknüpfung, Weiterverarbeitung), entscheidet allein das Skript. Details und Beispiele: Scripting.
HTTP-Methode
Welche Funktion aufgerufen wird, ergibt sich aus dem HTTP-Verb: Der Server ruft
die gleichnamige Skript-Methode auf (Get/Post/Put/Delete/Patch).
Ein Template entspricht damit einem Endpunkt-Skript; unterschiedliche
Pfad-Formen (z. B. /orders vs. /orders/{uid}) sind
eigene Endpunkt-Einträge mit eigenem Skript und eigener Berechtigung.
URL-Struktur
http://[Host][:Port][Pfad-Template]
Beispiele:
https://api.meinserver.de/ordershttps://api.meinserver.de/orders/4711https://api.meinserver.de/orders/4711/modules/A1
Versionierung
Da es kein eigenes Versions-Feld mehr gibt, wird die Version als statisches
Segment ins Template aufgenommen, z. B. /orders/v1 oder
/v1/orders/{uid}. Änderung ohne Breaking Change:
- Bestehenden Endpunkt unverändert lassen.
- Neuen Endpunkt mit gleichem Ressourcennamen, aber neuem Versions-Segment im Template anlegen.
- Berechtigungen für neue Konsumenten setzen.
- Alten Endpunkt deaktivieren, wenn die Migration abgeschlossen ist.
Zugriffskontrolle
Endpunkte sind Server-Profilen zugeordnet; ein Zugang benötigt eine explizite
Berechtigung (Tabelle RESTSRV_ACCESS), um einen Endpunkt nutzen zu
dürfen. Weil jede Pfad-Form ein eigener Endpunkt-Eintrag ist, lässt sich der
Zugriff pro Pfad-Form granular vergeben (z. B. Lesen von
/orders/{uid} erlauben, aber das ändernde
PUT /orders/{uid}/modules/{code} nicht).
Caching
Die Endpunkt-Definitionen werden pro Server-Profil zwischengespeichert (TTL, Standard 60 s). Neue oder geänderte Endpunkte/Templates werden daher erst nach Ablauf des Caches (bzw. nach einer Cache-Invalidierung) wirksam – nicht zwingend sofort.
HTTP-Fehlercodes
| Code | Ursache |
|---|---|
| 404 | Kein Template passt zum Pfad, Endpunkt inaktiv oder falsches Server-Profil |
| 403 | Zugang fehlt in der Berechtigungsliste |
| 401 | API-Key ungültig/fehlend, JWT abgelaufen oder Sitzung gesperrt (AUTH_EXPIRED) |
| 500 | Skript- oder Syntax-Fehler (Details in RESTSRV_PROTO)
|
| 415 | Datei-Upload an einen Endpunkt, der dafür nicht freigeschaltet ist (re_upload = 0)
|
| 413 | Hochgeladene Datei überschreitet die zulässige Maximalgrösse (re_upload_size)
|
| 429 | Rate-Limit überschritten; die Antwort enthält den Header Retry-After
|
| 503 | Eine Anfrage mit demselben Idempotency-Key wird gerade verarbeitet; die Antwort enthält Retry-After
|
| 409 | Ein früherer Aufruf mit demselben Idempotency-Key ist ohne Ergebnis geblieben (IDEMPOTENCY_UNRESOLVED)
|
| 422 | Derselbe Idempotency-Key wurde mit anderem Inhalt gesendet (IDEMPOTENCY_KEY_REUSED)
|
| 400 | Die Anfrage wurde unverschlüsselt an einen TLS-Port geschickt (http statt https). Die Abweisung erfolgt vor Authentifizierung und Endpunkt-Skript
|
Jede Fehlerantwort besteht aus einem error-Objekt mit
maschinenlesbarem Code - Aufbau siehe
Übersicht.
Daneben kann ein Endpunkt-Skript den Statuscode selbst setzen (z.B. 201, 204, 409, 422) sowie Response-Header wie ETag oder Location - siehe Scripting.
Idempotenz
Schickt ein Konsument bei POST, PUT, PATCH
oder DELETE den Header Idempotency-Key, sorgt der Server
selbst dafür, dass eine wiederholte Sendung keine Zweitwirkung hat. Das gilt
für jeden Endpunkt - es muss weder am Endpunkt etwas eingestellt noch im
Skript etwas programmiert werden.
| Situation | Antwort des Servers |
|---|---|
| Erster Aufruf | Endpunkt läuft normal, das Ergebnis wird zum Schlüssel gespeichert |
| Wiederholung, gleicher Inhalt | Gespeicherte Antwort (gleicher Statuscode, gleicher Body, gleiche Header) plus Header Idempotent-Replay: true. Das Skript läuft nicht
|
| Wiederholung, anderer Inhalt | 422 IDEMPOTENCY_KEY_REUSED - derselbe Schlüssel für einen anderen Inhalt ist ein Client-Fehler
|
| Erster Aufruf läuft noch | 503 IDEMPOTENCY_IN_PROGRESS mit Retry-After. Beim nächsten Versuch liegt die gespeicherte Antwort vor
|
| Früherer Aufruf ohne Ergebnis | 409 IDEMPOTENCY_UNRESOLVED. Der Dienst wurde zwischen Verarbeitung und Festschreiben unterbrochen; ob die Buchung stattgefunden hat, ist unbekannt und von Hand zu klären
|
Wichtig für die Auslegung eines Endpunkts:
- Antwortet das Skript mit 2xx, wird die Antwort gespeichert und bei einer Wiederholung erneut ausgeliefert.
- Antwortet das Skript mit 4xx (fachliche Ablehnung), wird der Schlüssel wieder freigegeben - der Konsument darf ihn nach Korrektur erneut verwenden. Sonst würde ein einziger Validierungsfehler den Schlüssel dauerhaft blockieren.
- Endet die Verarbeitung mit 5xx oder einem Skript-Fehler, bleibt der Schlüssel belegt und der Fall wird protokolliert. Das ist Absicht: lieber ein Fall für den Support als eine mögliche Doppelbuchung.
Der Schlüssel gilt je Zugang, Methode und Pfad. Derselbe
Idempotency-Key an einem anderen Endpunkt ist damit ein eigener
Vorgang - der Konsument muss ihn nicht global eindeutig vergeben, aber pro Vorgang
stabil wiederverwenden (also nicht bei jedem Wiederholversuch neu erzeugen).
Die Einträge stehen in RESTSRV_IDEMPOTENCY und werden nach 30 Tagen
automatisch aufgeräumt. Einträge ohne Ergebnis werden nicht automatisch
gelöscht, sondern im Protokoll gemeldet.
WebHooks
WebHooks sind Einmal-Endpunkte für asynchrone Callbacks. Beim ersten
erfolgreichen Aufruf wird die Antwort in der Tabelle REMOTE_HOOK_URL
gespeichert und der Endpunkt anschließend automatisch gelöscht.
Typischer Einsatz: OBS stösst einen Vorgang bei einem Fremdsystem an (Bezahldienst, Versanddienstleister) und gibt diesem eine Rückruf-Adresse mit, die nur ein einziges Mal gültig ist. Damit kann die Adresse nicht später erneut - oder von jemand anderem - benutzt werden.
Ablauf:
- OBS legt einen Eintrag in
REMOTE_HOOK_URLan und dazu einen Endpunkt, dessen Feld WebHook (re_webhook) auf diesen Eintrag zeigt. Ein Skript wird für diesen Endpunkt nicht gepflegt. - Die Adresse dieses Endpunkts wird dem Fremdsystem als Callback-URL übergeben.
- Das Fremdsystem ruft die Adresse auf. Der Server legt den übergebenen Inhalt in
REMOTE_HOOK_URL.hu_responseab, antwortet mit{"status": "ok"}und löscht den Endpunkt. - Der weiterverarbeitende OBS-Prozess findet die Rückmeldung in
hu_response.
existiert nicht mehr, die Antwort ist 404. Das ist gewollt - ein WebHook ist keine dauerhafte Schnittstelle. Für eine dauerhaft erreichbare Rückmelde-Adresse einen
normalen Endpunkt mit Skript anlegen.