OBS/Kostenpflichtige Module/RESTServer/Scripting: Unterschied zwischen den Versionen

Aus OBS Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
 
Zeile 78: Zeile 78:


Diese Werte werden vom Server gesetzt und können vom Skript für Berechtigungs- und Mandantenprüfungen verwendet werden.
Diese Werte werden vom Server gesetzt und können vom Skript für Berechtigungs- und Mandantenprüfungen verwendet werden.
===Pfad-Parameter===
Stammt der Endpunkt aus einem Pfad-Template mit Platzhaltern (siehe [[OBS/Kostenpflichtige Module/RESTServer/Endpunkte|Endpunkte]]), stehen die aus den Platzhaltern erfassten Werte als reservierte Parameter mit Präfix '''_OBS_PATH_''' in ''oParams'' bereit:
{| class="wikitable"
! Template !! Zugriff im Skript
|-
| <code>/orders/{uid}</code> || ''oParams.Values['_OBS_PATH_uid']''
|-
| <code>/orders/{uid}/modules/{code}</code> || ''oParams.Values['_OBS_PATH_uid']'', ''oParams.Values['_OBS_PATH_code']''
|}
Da der Präfix ''_OBS_'' für von aussen gelieferte Header- und Query-Parameter gesperrt ist, sind diese Werte nicht durch den Client fälschbar. Ein vollständiges Beispiel zeigt [[OBS/Kostenpflichtige Module/RESTServer/Beispiel4|Beispiel 4 - Pfad-Parameter]].


==Rückgabe==
==Rückgabe==
Zeile 181: Zeile 195:
==Skript-Cache==
==Skript-Cache==


Der Server cached das kompilierte Skript pro Endpunkt. Änderungen am Skript über F7 sind sofort wirksam - der Server erkennt die Änderung am ''sys_date'' und compiliert neu.
Der Server cached das kompilierte Skript pro Endpunkt (Schlüssel: ''sys_date'' des Endpunkts). Zusätzlich werden die Endpunkt-Definitionen pro Server-Profil in einem TTL-Cache (Standard 60 s) gehalten. Eine Skript-Änderung über F7 wird daher erst nach Ablauf dieses TTL (bzw. nach einer Cache-Invalidierung) wirksam - typischerweise innerhalb einer Minute, nicht zwingend sofort.


==Verfügbare Bibliotheken==
==Verfügbare Bibliotheken==
Zeile 197: Zeile 211:
* [[OBS/Kostenpflichtige Module/RESTServer/Beispiel1|Beispiel: Daten-Abruf mit JWT]]
* [[OBS/Kostenpflichtige Module/RESTServer/Beispiel1|Beispiel: Daten-Abruf mit JWT]]
* [[OBS/Kostenpflichtige Module/RESTServer/Beispiel2|Beispiel: Datensatz anlegen mit JSON-Body]]
* [[OBS/Kostenpflichtige Module/RESTServer/Beispiel2|Beispiel: Datensatz anlegen mit JSON-Body]]
* [[OBS/Kostenpflichtige Module/RESTServer/Beispiel4|Beispiel: Pfad-Parameter im Routing]]

Aktuelle Version vom 15. Juni 2026, 08:24 Uhr

Kostenpflichtige Module

Internet-Shop
UPS
IMS Professional
SMS
Mehrlager-Verwaltung
Mehrsprachen Modul
Multilanguage Modul
EVA Marketing Tool
Termin-Projekte
Edifact-Schnittstelle
Backup Überwachung Email
OBS Geo Daten
DeliSprint / DPD
Filialen
Cashback
Moebelschnittstelle
Dokumenten Manager
DocuWare-Schnittstelle
OFML-Kalkulation
Versicherungsschaden
Gutschriftsanzeigen
Kameraverwaltung
DataInOut
OpenMasterData / IDS
Sammelpositionen


Anleitung für 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

HINWEIS: Endpunkt-Skripte verarbeiten Daten aus dem Internet. Übergabeparameter dürfen niemals ungeprüft in SQL-Anweisungen eingebaut werden. Werte immer über DB_SQLVal bzw. Parameter-Bindings absichern, Eingabewerte gegen Whitelists prüfen.
  • Eingaben gegen erwartete Werte prüfen (z.B. Pflichtfelder, erlaubte Typen, Wertebereiche).
  • Nur das zurückgeben, was der Konsument wirklich braucht - keine internen IDs, keine Sys-Felder, keine Passwörter.
  • Bei Fehlern keine internen Details an den Konsumenten zurückgeben; stattdessen schreibt der Server ohnehin Detail-Einträge 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-ähnliche Fehler über die generische Skript-Antwort.

Parameter

oParams (TStrings)

Enthält 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 Präfix _OBS_ können von aussen nicht gesetzt werden; sie sind für 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)

Enthält den Request-Body, sofern dieser ein gültiges JSON-Objekt ist. Bei leerem oder nicht-JSON-Body wird nil übergeben.

cUser := ;
cPass := ;
if (Assigned(oBody)) then begin
    oVal := oBody.GetValue('username');
    if (Assigned(oVal)) then begin
        cUser := oVal.Value;
    end;
    oVal := oBody.GetValue('password');
    if (Assigned(oVal)) then begin
        cPass := oVal.Value;
    end;
end;

Maximale Body-Grösse: 10 MB.

Reservierte _OBS_-Parameter

Bei aktiver JWT-Authentifizierung stehen die Token-Claims als Parameter zur Verfügung:

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 können vom Skript für Berechtigungs- und Mandantenprüfungen verwendet werden.

Pfad-Parameter

Stammt der Endpunkt aus einem Pfad-Template mit Platzhaltern (siehe Endpunkte), stehen die aus den Platzhaltern erfassten Werte als reservierte Parameter mit Präfix _OBS_PATH_ in oParams bereit:

Template Zugriff im Skript
/orders/{uid} oParams.Values['_OBS_PATH_uid']
/orders/{uid}/modules/{code} oParams.Values['_OBS_PATH_uid'], oParams.Values['_OBS_PATH_code']

Da der Präfix _OBS_ für von aussen gelieferte Header- und Query-Parameter gesperrt ist, sind diese Werte nicht durch den Client fälschbar. Ein vollständiges Beispiel zeigt Beispiel 4 - Pfad-Parameter.

Rückgabe

Die Rückgabe ist immer ein JSON-String. Wird ein leerer String zurückgegeben, 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;

JWT-Authentifizierungs-Skript

Bei Zugängen mit aktiver JWT-Pflicht wird über den JWT-Endpunkt das im Zugang hinterlegte Authentifizierungs-Skript aufgerufen (F7 in der Zugänge-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)
        cUser := '';
        cPass := '';
        if (Assigned(oBody)) then begin
            oVal := oBody.GetValue('username');
            if (Assigned(oVal)) then begin
                cUser := oVal.Value;
            end;
            oVal := oBody.GetValue('password');
            if (Assigned(oVal)) then begin
                cPass := oVal.Value;
            end;
        end;

        // Prüfung 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;

Rückgabewerte:

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 schlägt die Syntax-Prüfung 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 zurückgeben, 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 (Schlüssel: sys_date des Endpunkts). Zusätzlich werden die Endpunkt-Definitionen pro Server-Profil in einem TTL-Cache (Standard 60 s) gehalten. Eine Skript-Änderung über F7 wird daher erst nach Ablauf dieses TTL (bzw. nach einer Cache-Invalidierung) wirksam - typischerweise innerhalb einer Minute, nicht zwingend sofort.

Verfügbare Bibliotheken

Im Skript können 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: