OBS/Kostenpflichtige Module/RESTServer/Scripting
- 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
Anleitung fuer Endpunkt-Skripte
Jede Anfrage an einen Endpunkt wird nach erfolgreicher Authentifizierung und Autorisierung an das hinterlegte Skript weitergegeben. Das Skript ist in Object Pascal geschrieben und greift auf die OBS-Bibliothek (DB-Zugriff, Hilfsfunktionen) zu.
Sicherheitshinweise
- Eingaben gegen erwartete Werte pruefen (z.B. Pflichtfelder, erlaubte Typen, Wertebereiche).
- Nur das zurueckgeben, was der Konsument wirklich braucht - keine internen IDs, keine Sys-Felder, keine Passwoerter.
- Bei Fehlern keine internen Details an den Konsumenten zurueckgeben; stattdessen schreibt der Server ohnehin Detail-Eintraege in RESTSRV_PROTO.
Methoden-Signatur
Pro HTTP-Methode wird im Skript eine gleichnamige Funktion implementiert. Der Server ruft genau die Funktion auf, die zur Methode des eingehenden Requests passt.
function Get (oParams: TStrings; oBody: TJSONObject): string; function Post (oParams: TStrings; oBody: TJSONObject): string; function Put (oParams: TStrings; oBody: TJSONObject): string; function Delete(oParams: TStrings; oBody: TJSONObject): string; function Patch (oParams: TStrings; oBody: TJSONObject): string;
Nicht implementierte Methoden liefern automatisch 405-aehnliche Fehler ueber die generische Skript-Antwort.
Parameter
oParams (TStrings)
Enthaelt alle Query-Parameter, POST-Parameter (form-urlencoded) sowie die durchgereichten HTTP-Header. Werte sind immer Strings.
Filterung durch den Server:
- Geblockte Header werden nicht durchgereicht: authorization, cookie, proxy-authorization, x-forwarded-for, x-real-ip, apikey, api_key.
- Parameter mit Praefix _OBS_ koennen von aussen nicht gesetzt werden; sie sind fuer interne Werte reserviert.
- Werte werden auf max. 1024 Zeichen begrenzt.
- Null-Bytes und Steuerzeichen (ausser Tab, CR, LF) werden entfernt.
Zugriff im Skript:
if (not Empty(oParams.Values['kundennr'])) then begin
cKundenNr := oParams.Values['kundennr'];
end;
oBody (TJSONObject)
Enthaelt den Request-Body, sofern dieser ein gueltiges JSON-Objekt ist. Bei leerem oder nicht-JSON-Body wird nil uebergeben.
if (Assigned(oBody)) then begin
oBody.TryGetValue<string>('email', cEmail);
oBody.TryGetValue<integer>('menge', nMenge);
end;
Maximale Body-Groesse: 10 MB.
Reservierte _OBS_-Parameter
Bei aktiver JWT-Authentifizierung stehen die Token-Claims als Parameter zur Verfuegung:
| Parameter | Inhalt |
|---|---|
| _OBS_JWT_ID | JWT-Id (jti-Claim) - typisch die User-Id |
| _OBS_JWT_SUBJECT | Subject (sub-Claim) - typisch Benutzername |
| _OBS_JWT_AUDIENCE | Audience (aud-Claim) - typisch Mandant / Rolle |
Diese Werte werden vom Server gesetzt und koennen vom Skript fuer Berechtigungs- und Mandantenpruefungen verwendet werden.
Rueckgabe
Die Rueckgabe ist immer ein JSON-String. Wird ein leerer String zurueckgegeben, antwortet der Server automatisch mit {}. Der Server setzt Content-Type auf application/json; charset=utf-8 und Status auf 200, sofern das Skript nicht selbst einen Fehler signalisiert.
Einfaches Beispiel:
function Get(oParams: TStrings; oBody: TJSONObject): string;
var oRes: TJSONObject;
begin
oRes := TJSONObject.Create();
try
oRes.AddPair('wert_string', '123');
oRes.AddPair('wert_int' , 456);
result := oRes.ToJSON();
finally
MyFreeAndNil(oRes);
end;
end;
Datenbank-Zugriff
Innerhalb eines Skripts steht die globale OBS-Datenbankverbindung oDB zur Verfuegung. Jeder Request bekommt eine eigene Verbindung aus dem DB-Connection-Pool, das Skript muss daher nicht selbst auf Thread-Sicherheit achten.
Lese-Beispiel:
var cSql : string;
qData : TxFQuery;
begin
cSql := 'SELECT ku_name1 FROM kunden WHERE ku_nr = ' + DB_SQLVal(oParams.Values['kundennr']);
if (DB_SOpen('Y00C71XXAA', oDB, cSql, qData)) then begin
// Verarbeitung
end;
DB_Close(qData);
end;
JWT-Authentifizierungs-Skript
Bei Zugaengen mit aktiver JWT-Pflicht wird ueber den JWT-Endpunkt das im Zugang hinterlegte Authentifizierungs-Skript aufgerufen (F7 in der Zugaenge-Liste). Das Skript muss eine Methode Authenticate bereitstellen:
function Authenticate(oParams: TStrings; oBody: TJSONObject): string;
var oRes : TJSONObject;
cUser : string;
cPass : string;
begin
oRes := TJSONObject.Create();
try
// Eingangsdaten lesen (Body oder Query-Param)
if (Assigned(oBody)) then begin
oBody.TryGetValue<string>('username', cUser);
oBody.TryGetValue<string>('password', cPass);
end;
// Pruefung gegen eigene Tabelle, Hash-Verfahren, LDAP, ...
if (PasswortPasst(cUser, cPass)) then begin
oRes.AddPair('status' , 1);
oRes.AddPair('_OBS_JWT_ID' , cUser);
oRes.AddPair('_OBS_JWT_SUBJECT', cUser);
oRes.AddPair('_OBS_JWT_AUDIENCE', 'mandant1');
end else begin
oRes.AddPair('status', 9);
oRes.AddPair('error' , 'Login fehlgeschlagen');
end;
result := oRes.ToJSON();
finally
MyFreeAndNil(oRes);
end;
end;
Rueckgabewerte:
| status | Bedeutung |
|---|---|
| 1 | Erfolgreich, der Server erzeugt aus den _OBS_JWT_*-Werten einen Token (HS256) |
| 9 | Misserfolg, der Server antwortet mit 403 und protokolliert den Wert von error |
Fehlerbehandlung im Skript
Tritt im Skript eine Exception auf oder schlaegt die Syntax-Pruefung fehl, antwortet der Server mit 500 Interner Fehler und protokolliert die Detail-Meldung in RESTSRV_PROTO (mit Skript-Fehlertext). Der Konsument sieht keine internen Details.
Will das Skript einen spezifischen Fehler an den Konsumenten zurueckgeben, ist eine eigene JSON-Struktur zu liefern:
function Post(oParams: TStrings; oBody: TJSONObject): string;
var oRes: TJSONObject;
begin
oRes := TJSONObject.Create();
try
if (Empty(oParams.Values['kundennr'])) then begin
oRes.AddPair('status', 'error');
oRes.AddPair('msg' , 'Parameter ''kundennr'' fehlt');
result := oRes.ToJSON();
exit;
end;
// ...
finally
MyFreeAndNil(oRes);
end;
end;
Skript-Cache
Der Server cached das kompilierte Skript pro Endpunkt. Aenderungen am Skript ueber F7 sind sofort wirksam - der Server erkennt die Aenderung am sys_date und compiliert neu.
Verfuegbare Bibliotheken
Im Skript koennen alle OBS-Standard-Bibliotheken verwendet werden. Typische Einstiegspunkte:
- Base.Tools - String-, Datum-, IIF-, Empty-Helper
- Base.DB / Base.xQuery - Datenbank-Operationen, DB_SQLVal, DB_SOpen, DB_LSeek
- Base.qSqlReg - qSqlInit, qSet, SaveData
- System.JSON - JSON-Objekte und -Arrays
- Base.ToolsConst - Konstanten wie CRLF, SINGELQUOTE, EMPTY_DATE
Konkrete Beispiele: