OBS/Kostenpflichtige Module/RESTServer/Beispiel4: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 16: | Zeile 16: | ||
Die Platzhalter <code>{uid}</code> und <code>{code}</code> stehen im Skript als | Die Platzhalter <code>{uid}</code> und <code>{code}</code> stehen im Skript als | ||
<code> | <code>oReader.Path('uid')</code> bzw. <code>oReader.Path('code')</code> zur | ||
<code> | Verfügung. | ||
== Einrichtung in OBS == | == Einrichtung in OBS == | ||
| Zeile 38: | Zeile 38: | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
// Hilfsfunktion: | // Hilfsfunktion: die FELDER eines Auftrags. Der Helfer bekommt den Writer und | ||
// | // schreibt in das Objekt, das der Aufrufer schon geoeffnet hat - so laesst sich | ||
// | // derselbe Auftrag einmal als Listeneintrag und einmal als ganze Antwort | ||
// ausgeben, ohne den Code zu verdoppeln. | |||
procedure _OrderFelder(oWriter: TxRestWriter; qOrder: TqSQL; | |||
const cOffset: string); | |||
begin | begin | ||
oWriter.Str ('uid' , qOrder.A2UID()); | |||
oWriter.Str ('nr' , qOrder.A2C('au_nr')); | |||
oWriter.Str ('kunde' , qOrder.A2C('au_kunde')); | |||
oWriter.Str ('status', qOrder.A2C('au_status')); | |||
// ISO-8601 mit Offset - siehe den Hinweis unter der Liste. | |||
oWriter.StrN('aenderung', RestIsoFromDate(qOrder.A2D('au_aend_dat'), cOffset)); | |||
end; | end; | ||
procedure Get(oReader: TxRestReader; oWriter: TxRestWriter); | |||
var cSql : string; | var cSql : string; | ||
qData: TqSQL; | qData : TqSQL; | ||
cOffset: string; | |||
begin | begin | ||
cOffset := oReader.Offset(); | |||
// Die Antwort ist eine nackte Liste - RootArr vor dem ersten Eintrag. | |||
// Findet die Abfrage nichts, ist es eine leere Liste und kein leeres | |||
// Objekt: deshalb steht der Aufruf VOR der Abfrage. | |||
oWriter.RootArr(); | |||
cSql := 'SELECT * FROM auftraege' + | cSql := 'SELECT * FROM auftraege' + | ||
| Zeile 77: | Zeile 69: | ||
if (DB_SOpen(oDB, cSql, qData)) then begin | if (DB_SOpen(oDB, cSql, qData)) then begin | ||
while (not qData.EoF) do begin | while (not qData.EoF) do begin | ||
oWriter.ObjBegin(''); | |||
_OrderFelder(oWriter, qData, cOffset); | |||
oWriter.ObjEnd; | |||
qData.Next(); | qData.Next(); | ||
end; | end; | ||
end; | end; | ||
DB_Close(qData); | |||
end; | end; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 89: | Zeile 82: | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
//-- | // Derselbe Helfer wie im Listen-Skript - hier schreibt er in die WURZEL, weil | ||
// | // der Auftrag selbst die Antwort ist. Eine eigene Fehlerfunktion braucht es | ||
// | // nicht mehr: oWriter.Error setzt Statuscode, code, message, uid und traceId. | ||
//-- | // Derselbe Helfer wie im Listen-Skript - hier schreibt er in die WURZEL, | ||
// weil der Auftrag selbst die Antwort ist. | |||
procedure _OrderFelder(oWriter: TxRestWriter; qOrder: TqSQL; | |||
const cOffset: string); | |||
begin | begin | ||
oWriter.Str ('uid' , qOrder.A2UID()); | |||
oWriter.Str ('nr' , qOrder.A2C('au_nr')); | |||
oWriter.Str ('kunde' , qOrder.A2C('au_kunde')); | |||
oWriter.Str ('status', qOrder.A2C('au_status')); | |||
oWriter.StrN('aenderung', RestIsoFromDate(qOrder.A2D('au_aend_dat'), cOffset)); | |||
end; | end; | ||
procedure Get(oReader: TxRestReader; oWriter: TxRestWriter); | |||
var cUid : string; | |||
cSql : string; | |||
qData : TqSQL; | |||
lGefunden: Boolean; | |||
cOffset : string; | |||
begin | begin | ||
// Pfad-Parameter aus /orders/{uid} | // Pfad-Parameter aus /orders/{uid} | ||
cUid := | cUid := oReader.Path('uid'); | ||
cOffset := oReader.Offset(); | |||
if (cUid = '') then begin | if (cUid = '') then begin | ||
oWriter.Error(422, 'VALIDATION_FAILED', 'Pfad-Parameter "uid" fehlt'); | |||
exit; | exit; | ||
end; | end; | ||
lGefunden := false; | |||
cSql := 'SELECT * FROM auftraege WHERE sys_uid = ' + DB_SQLVal(cUid); | cSql := 'SELECT * FROM auftraege WHERE sys_uid = ' + DB_SQLVal(cUid); | ||
if (DB_SOpen(oDB, cSql, qData)) | if (DB_SOpen(oDB, cSql, qData)) then begin | ||
if (not qData.EoF) then begin | |||
_OrderFelder(oWriter, qData, cOffset); | |||
lGefunden := true; | |||
end; | |||
end; | |||
DB_Close(qData); | |||
if (not lGefunden) then begin | |||
oWriter.Error(404, 'NOT_FOUND', 'Auftrag nicht gefunden'); | |||
end; | end; | ||
end; | end; | ||
| Zeile 147: | Zeile 131: | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
procedure Put(oReader: TxRestReader; oWriter: TxRestWriter); | |||
var cUid : string; | var cUid : string; | ||
cCode : string; | cCode : string; | ||
| Zeile 182: | Zeile 142: | ||
begin | begin | ||
// Beide Pfad-Parameter | // Beide Pfad-Parameter | ||
cUid := | cUid := oReader.Path('uid'); | ||
cCode := | cCode := oReader.Path('code'); | ||
if (cUid = '') or (cCode = '') then begin | if (cUid = '') or (cCode = '') then begin | ||
oWriter.Error(422, 'VALIDATION_FAILED', 'Pfad-Parameter "uid" oder "code" fehlt'); | |||
exit; | exit; | ||
end; | end; | ||
// Nutzdaten kommen aus dem JSON-Body | // Nutzdaten kommen aus dem JSON-Body. Der Rueckgabewert sagt, ob das Feld | ||
cStatus := | // ueberhaupt gesendet wurde - eine eigene Hilfsfunktion dafuer braucht es | ||
// nicht mehr. | |||
cStatus := ''; | |||
oReader.Str('status', cStatus); | |||
if (cStatus = '') then begin | if (cStatus = '') then begin | ||
oWriter.Error(422, 'VALIDATION_FAILED', 'Feld "status" fehlt'); | |||
exit; | exit; | ||
end; | end; | ||
| Zeile 210: | Zeile 173: | ||
if (cModUid = '') then begin | if (cModUid = '') then begin | ||
oWriter.Error(404, 'NOT_FOUND', 'Modul nicht gefunden'); | |||
exit; | exit; | ||
end; | end; | ||
| Zeile 226: | Zeile 189: | ||
if (not lOk) then begin | if (not lOk) then begin | ||
oWriter.Error(500, 'INTERNAL_ERROR', 'Status konnte nicht gespeichert werden'); | |||
exit; | exit; | ||
end; | end; | ||
oWriter.Str('status', 'ok'); | |||
end; | end; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 254: | Zeile 217: | ||
* '''Eine Ressource, mehrere Pfad-Formen''' über getrennte Endpunkt-Einträge mit eigenem Skript und eigener Berechtigung. | * '''Eine Ressource, mehrere Pfad-Formen''' über getrennte Endpunkt-Einträge mit eigenem Skript und eigener Berechtigung. | ||
* '''Pfad-Parameter''' werden über <code>{name}</code> im Template erfasst und im Skript | * '''Pfad-Parameter''' werden über <code>{name}</code> im Template erfasst und im Skript mit <code>oReader.Path('name')</code> gelesen. | ||
* Reihenfolge der Skript-Parameter: '''<code> | * Reihenfolge der Skript-Parameter: '''<code>oReader</code> zuerst, <code>oWriter</code> danach'''. | ||
* '''Ein Helfer bekommt den Writer''' und schreibt an der Stelle hinein, an der er gerufen wird. Derselbe <code>_OrderFelder</code> bedient den Listeneintrag und die Einzelantwort - einmal in einem <code>ObjBegin('')</code>, einmal in der Wurzel. | |||
* Präzedenz: ein statisches Segment (z. B. <code>/orders/summary</code>) hätte Vorrang vor <code>/orders/{uid}</code>. | * Präzedenz: ein statisches Segment (z. B. <code>/orders/summary</code>) hätte Vorrang vor <code>/orders/{uid}</code>. | ||
Aktuelle Version vom 9. September 2026, 13:31 Uhr
Internet-Shop
Der modified ECommerce Shop
Shop-Menü
- 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
Automatische Vorgänge
Preislisten
ZUGFeRD
Factoring
UPS
IMS Professional
SMS
Mehrlager-Verwaltung
Mehrsprachen Modul
Multilanguage Modul
Einfache Produktionsnachverfolgung
DMS - Dokumenten Management System
DMS Dokumente
Tasten und Schaltflächen
F10 Weit.
QR Zeiterfassung
EVA Marketing Tool
Technikersteuerung
Termin-Projekte
Edifact-Schnittstelle
Backup Überwachung Email
Anlagenbuchhaltung
OBS Geo Daten
DeliSprint / DPD
Filialen
Auto-Waagen
Cashback
Moebelschnittstelle
Tourenplanung
Dokumenten Manager
DocuWare-Schnittstelle
OFML-Kalkulation
Pascom
Versicherungsschaden
Gutschriftsanzeigen
OCPP Ladestationen
Kameraverwaltung
DataInOut
REST-Schnittstelle
Sammelverträge
Craftboxx
OpenMasterData / IDS
Sammelpositionen
KI-Mining
Beispiel 4 – Pfad-Parameter (REST-Routing über Templates)
Dieses Beispiel zeigt das Pfad-Template-Routing mit Platzhaltern. Eine Auftrags-Ressource wird über drei Endpunkte abgebildet:
| Methode + Pfad | Zweck |
|---|---|
GET /orders |
Liste aller offenen Aufträge |
GET /orders/{uid} |
Einzelner Auftrag per UID |
PUT /orders/{uid}/modules/{code} |
Status eines Auftrags-Moduls ändern |
Die Platzhalter {uid} und {code} stehen im Skript als
oReader.Path('uid') bzw. oReader.Path('code') zur
Verfügung.
Einrichtung in OBS
- Server-Profil: Standard-TLS-Profil Public-API auf
0.0.0.0:443. - Zugang: Orders-Client mit API-Key, Zugriff auf die drei Endpunkte.
- Endpunkte (je ein Eintrag in
RESTSRV_ENDPOINTS, alle Profil Public-API):
| Endpunkt | Pfad-Template | Skript-Methode |
|---|---|---|
orders |
/orders |
Get (Liste)
|
orders |
/orders/{uid} |
Get (Einzel)
|
orders |
/orders/{uid}/modules/{code} |
Put
|
Endpunkt-Skript 1: GET /orders (Liste)
// Hilfsfunktion: die FELDER eines Auftrags. Der Helfer bekommt den Writer und
// schreibt in das Objekt, das der Aufrufer schon geoeffnet hat - so laesst sich
// derselbe Auftrag einmal als Listeneintrag und einmal als ganze Antwort
// ausgeben, ohne den Code zu verdoppeln.
procedure _OrderFelder(oWriter: TxRestWriter; qOrder: TqSQL;
const cOffset: string);
begin
oWriter.Str ('uid' , qOrder.A2UID());
oWriter.Str ('nr' , qOrder.A2C('au_nr'));
oWriter.Str ('kunde' , qOrder.A2C('au_kunde'));
oWriter.Str ('status', qOrder.A2C('au_status'));
// ISO-8601 mit Offset - siehe den Hinweis unter der Liste.
oWriter.StrN('aenderung', RestIsoFromDate(qOrder.A2D('au_aend_dat'), cOffset));
end;
procedure Get(oReader: TxRestReader; oWriter: TxRestWriter);
var cSql : string;
qData : TqSQL;
cOffset: string;
begin
cOffset := oReader.Offset();
// Die Antwort ist eine nackte Liste - RootArr vor dem ersten Eintrag.
// Findet die Abfrage nichts, ist es eine leere Liste und kein leeres
// Objekt: deshalb steht der Aufruf VOR der Abfrage.
oWriter.RootArr();
cSql := 'SELECT * FROM auftraege' +
' WHERE au_status <> ' + DB_SQLVal('9') +
' ORDER BY au_nr';
if (DB_SOpen(oDB, cSql, qData)) then begin
while (not qData.EoF) do begin
oWriter.ObjBegin('');
_OrderFelder(oWriter, qData, cOffset);
oWriter.ObjEnd;
qData.Next();
end;
end;
DB_Close(qData);
end;Endpunkt-Skript 2: GET /orders/{uid} (Einzel)
// Derselbe Helfer wie im Listen-Skript - hier schreibt er in die WURZEL, weil
// der Auftrag selbst die Antwort ist. Eine eigene Fehlerfunktion braucht es
// nicht mehr: oWriter.Error setzt Statuscode, code, message, uid und traceId.
// Derselbe Helfer wie im Listen-Skript - hier schreibt er in die WURZEL,
// weil der Auftrag selbst die Antwort ist.
procedure _OrderFelder(oWriter: TxRestWriter; qOrder: TqSQL;
const cOffset: string);
begin
oWriter.Str ('uid' , qOrder.A2UID());
oWriter.Str ('nr' , qOrder.A2C('au_nr'));
oWriter.Str ('kunde' , qOrder.A2C('au_kunde'));
oWriter.Str ('status', qOrder.A2C('au_status'));
oWriter.StrN('aenderung', RestIsoFromDate(qOrder.A2D('au_aend_dat'), cOffset));
end;
procedure Get(oReader: TxRestReader; oWriter: TxRestWriter);
var cUid : string;
cSql : string;
qData : TqSQL;
lGefunden: Boolean;
cOffset : string;
begin
// Pfad-Parameter aus /orders/{uid}
cUid := oReader.Path('uid');
cOffset := oReader.Offset();
if (cUid = '') then begin
oWriter.Error(422, 'VALIDATION_FAILED', 'Pfad-Parameter "uid" fehlt');
exit;
end;
lGefunden := false;
cSql := 'SELECT * FROM auftraege WHERE sys_uid = ' + DB_SQLVal(cUid);
if (DB_SOpen(oDB, cSql, qData)) then begin
if (not qData.EoF) then begin
_OrderFelder(oWriter, qData, cOffset);
lGefunden := true;
end;
end;
DB_Close(qData);
if (not lGefunden) then begin
oWriter.Error(404, 'NOT_FOUND', 'Auftrag nicht gefunden');
end;
end;Endpunkt-Skript 3: PUT /orders/{uid}/modules/{code}
procedure Put(oReader: TxRestReader; oWriter: TxRestWriter);
var cUid : string;
cCode : string;
cStatus: string;
cSql : string;
qChk : TqSQL;
xMod : TqSQL;
cModUid: string;
lOk : Boolean;
begin
// Beide Pfad-Parameter
cUid := oReader.Path('uid');
cCode := oReader.Path('code');
if (cUid = '') or (cCode = '') then begin
oWriter.Error(422, 'VALIDATION_FAILED', 'Pfad-Parameter "uid" oder "code" fehlt');
exit;
end;
// Nutzdaten kommen aus dem JSON-Body. Der Rueckgabewert sagt, ob das Feld
// ueberhaupt gesendet wurde - eine eigene Hilfsfunktion dafuer braucht es
// nicht mehr.
cStatus := '';
oReader.Str('status', cStatus);
if (cStatus = '') then begin
oWriter.Error(422, 'VALIDATION_FAILED', 'Feld "status" fehlt');
exit;
end;
// Existenzpruefung - und zugleich der Schreib-Index. Ein SELECT auf die
// sys_uid liefert beides; ein 'SELECT *' waere hier verschenkte Arbeit.
cSql := 'SELECT sys_uid FROM auftrag_module' +
' WHERE am_auftrag = ' + DB_SQLVal(cUid) +
' AND am_code = ' + DB_SQLVal(cCode) + ' LIMIT 1';
cModUid := '';
if (DB_SOpen(oDB, cSql, qChk)) then begin
if (not qChk.EoF) then begin
cModUid := qChk.A2UID();
end;
end;
DB_Close(qChk);
if (cModUid = '') then begin
oWriter.Error(404, 'NOT_FOUND', 'Modul nicht gefunden');
exit;
end;
// Update
// Der Satz wird ueber seine sys_uid geschrieben - qSqlRead waere hier
// ein zusaetzlicher Lesezugriff, und ein unveraenderter Wert wuerde gar
// kein Write erzeugen (SaveData liefert dann False).
xMod := qSqlInit(oDB, 'auftrag_module');
xMod.qSet('sys_uid' , cModUid);
xMod.qSet('am_status', cStatus);
// Rueckgabewert auswerten - ein Schreibfehler wirft keine Exception
lOk := xMod.SaveData(UPDATE_RECORD);
qSqlFree(xMod);
if (not lOk) then begin
oWriter.Error(500, 'INTERNAL_ERROR', 'Status konnte nicht gespeichert werden');
exit;
end;
oWriter.Str('status', 'ok');
end;Test mit curl
# Liste
curl -H "apikey: GEHEIM123" https://api.meinserver.de/orders
# Einzelner Auftrag (uid als Pfad-Parameter)
curl -H "apikey: GEHEIM123" https://api.meinserver.de/orders/4711
# Modul-Status aendern (uid + code als Pfad-Parameter, status im Body)
curl -X PUT \
-H "apikey: GEHEIM123" \
-H "Content-Type: application/json" \
-d '{"status":"21"}' \
https://api.meinserver.de/orders/4711/modules/A1Was dieses Beispiel zeigt
- Eine Ressource, mehrere Pfad-Formen über getrennte Endpunkt-Einträge mit eigenem Skript und eigener Berechtigung.
- Pfad-Parameter werden über
{name}im Template erfasst und im Skript mitoReader.Path('name')gelesen. - Reihenfolge der Skript-Parameter:
oReaderzuerst,oWriterdanach. - Ein Helfer bekommt den Writer und schreibt an der Stelle hinein, an der er gerufen wird. Derselbe
_OrderFelderbedient den Listeneintrag und die Einzelantwort - einmal in einemObjBegin(), einmal in der Wurzel. - Präzedenz: ein statisches Segment (z. B.
/orders/summary) hätte Vorrang vor/orders/{uid}.