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

Aus OBS Wiki
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „Monster Legends is an island builder that permits the player to gather monsters and practice them for battles in the wild or against players. The characters a…“)
 
(Die Seite wurde neu angelegt: „{{Kostenpflichtige Module}} =Beispiel 2: Datensatz anlegen mit JSON-Body= Dieses Beispiel zeigt einen Endpunkt mit allen vier CRUD-Methoden (GET, POST, PUT, DELETE). Es geht um Tickets eines externen Servicedesks, der Tickets ueber den OBS REST-Server in OBS einliefern, abrufen, aktualisieren und schliessen kann. ==Einrichtung in OBS== * '''Server-Profil:''' Standard-TLS-Profil ''Public-API'', Bindung 0.0.0.0:443 * '''Zugang:''' ''Servicedesk-X'' ** A…“)
Zeile 1: Zeile 1:
Monster Legends is an island builder that permits the player to gather monsters and practice them for battles in the wild or against players. The characters are each sturdy and quite a few, but whereas there are countless forged members, unlike many shows where there are giant amounts of characters which are completely [https://www.Change.org/search?q=useless useless] and contribute nothing to the plot, every character in Monster brings one thing to the mix.<br><br>Rustic wood incorporates many natural traits including open and closed knots, pitch pockets, rasped edges, gouges, wormholes, small season checks, mineral streaks, dramatic shade [http://Www.europeana.eu/portal/search.html?query=distinction distinction] and different pure variations all reflecting the inherent beauty of the wooden.<br><br>It can be tempting to get caught up in the fun of breeding and elevating monsters, with out paying enough attention to the talents that you have unlocked for each of them (or the talents that you still have not unlocked!) Every monster has a different [http://get-gems.postbit.com/emotions-around-the-monster-legends-hack.html cheat in monster legends gems] assortment of abilities, and if you wish to reach battles-rather than just sitting around raising monsters all day-then you definately'll need to know what they're capable of!<br><br>To actually turn into the stuff of [http://mombao3.livejournal.com/620.html legends of tomorrow cast amaya], you will have to use the free BlueStacks Android Emulator to play Monster Legends on COMPUTER or Mac. The supporting solid is just as essential as a result of they are the means that help this anime arrive at a profitable end.<br><br>What separates Rings from other puzzle video games is it appears to do an excellent job of giving you a way out when the board is almost full. The level meter on the prime of the sport display screen exhibits how many XP you've collected and the remaining XP it is advisable to stage up.
{{Kostenpflichtige Module}}
 
=Beispiel 2: Datensatz anlegen mit JSON-Body=
 
Dieses Beispiel zeigt einen Endpunkt mit allen vier CRUD-Methoden (GET, POST, PUT, DELETE). Es geht um Tickets eines externen Servicedesks, der Tickets ueber den OBS REST-Server in OBS einliefern, abrufen, aktualisieren und schliessen kann.
 
==Einrichtung in OBS==
 
* '''Server-Profil:''' Standard-TLS-Profil ''Public-API'', Bindung 0.0.0.0:443
* '''Zugang:''' ''Servicedesk-X''
** API-Key: zufaellig generiert
** Host: ''servicedesk.kunde.de'' (DNS-gebunden, IP-Zugriff wird abgelehnt)
** JWT: nicht aktiv
* '''Endpunkt:''' ''tickets/v1'', Profil ''Public-API''
* '''Berechtigung:''' Zugang ''Servicedesk-X'' fuer Endpunkt ''tickets/v1'' freigeschaltet
 
==Endpunkt-Skript ''tickets/v1''==
 
<syntaxhighlight lang="pascal" line>
//------------------------------------------------------------------------------
// Hilfsfunktion: einzelnes Ticket als JSON-Objekt aufbauen
//------------------------------------------------------------------------------
 
function _TicketAsJSON(qTicket: TxFQuery): TJSONObject;
begin
    result := TJSONObject.Create();
    result.AddPair('id'        , qTicket.A2UID());
    result.AddPair('nr'        , qTicket.A2C('ti_nr'));
    result.AddPair('betreff'  , qTicket.A2C('ti_betreff'));
    result.AddPair('status'    , qTicket.A2C('ti_status'));
    result.AddPair('beschr'    , qTicket.A2C('ti_beschr'));
    result.AddPair('aenderung' , DTToSQL(qTicket.A2D('ti_aend_dat')));
end;
 
//------------------------------------------------------------------------------
// GET  /tickets/v1?id=...  - einzelnes Ticket
// GET  /tickets/v1          - alle offenen Tickets
//------------------------------------------------------------------------------
 
function Get(oBody: TJSONObject; oParams: TStrings): string;
var cSql  : string;
    qData : TxFQuery;
    oArr  : TJSONArray;
    cId  : string;
begin
    cId := oParams.Values['id'];
 
    if (not Empty(cId)) then begin
        cSql := 'SELECT * FROM tickets WHERE sys_uid = ' + DB_SQLVal(cId);
        if (DB_SOpen('Y00CXXXXBA', oDB, cSql, qData)) then begin
            result := _TicketAsJSON(qData).ToJSON();
        end else begin
            result := '{"error":"not found"}';
        end;
        DB_Close(qData);
    end else begin
        oArr := TJSONArray.Create();
        try
            cSql := 'SELECT * FROM tickets WHERE ti_status <> "9" ORDER BY ti_aend_dat DESC';
            if (DB_SOpen('Y00CXXXXBB', oDB, cSql, qData)) then begin
                while (not qData.EoF) do begin
                    oArr.Add(_TicketAsJSON(qData));
                    qData.Next();
                end;
            end;
            DB_Close(qData);
 
            result := oArr.ToJSON();
        finally
            MyFreeAndNil(oArr);
        end;
    end;
end;
 
//------------------------------------------------------------------------------
// POST  /tickets/v1          - neues Ticket anlegen
// Body: { "betreff":"...", "beschr":"..." }
//------------------------------------------------------------------------------
 
function Post(oBody: TJSONObject; oParams: TStrings): string;
var xTicket : TqSQL;
    cId    : string;
    cBetreff: string;
    cBeschr : string;
    oRes    : TJSONObject;
begin
    if (not Assigned(oBody)) then begin
        result := '{"error":"JSON-Body erforderlich"}';
        exit;
    end;
 
    cBetreff := '';
    cBeschr  := '';
    oBody.TryGetValue<string>('betreff', cBetreff);
    oBody.TryGetValue<string>('beschr' , cBeschr);
 
    if (Empty(cBetreff)) then begin
        result := '{"error":"Feld ''betreff'' fehlt"}';
        exit;
    end;
 
    cId := GetNewId(oDB);
 
    xTicket := qSqlInit('Y00CXXXXBC', oDB, 'tickets');
    xTicket.lNoSysUID := True;
    try
        xTicket.qSet('sys_uid'    , cId);
        xTicket.qSet('ti_nr'      , DB_NeuNum(oDB, 'tickets', 'ti_nr', NEUNUM_HOLE, '', '', 1, 999999, '0'));
        xTicket.qSet('ti_betreff' , cBetreff);
        xTicket.qSet('ti_beschr'  , cBeschr);
        xTicket.qSet('ti_status'  , '1');
        xTicket.qSet('ti_anl_dat' , Now());
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(NEW_RECORD);
    finally
        qSqlFree(xTicket);
    end;
 
    oRes := TJSONObject.Create();
    try
        oRes.AddPair('id'    , cId);
        oRes.AddPair('status', 'created');
        result := oRes.ToJSON();
    finally
        MyFreeAndNil(oRes);
    end;
end;
 
//------------------------------------------------------------------------------
// PUT  /tickets/v1          - Ticket aktualisieren
// Body: { "id":"...", "status":"...", "beschr":"..." }
//------------------------------------------------------------------------------
 
function Put(oBody: TJSONObject; oParams: TStrings): string;
var xTicket: TqSQL;
    cId    : string;
    cStat  : string;
    cBeschr: string;
begin
    if (not Assigned(oBody)) then begin
        result := '{"error":"JSON-Body erforderlich"}';
        exit;
    end;
 
    cId    := '';
    cStat  := '';
    cBeschr := '';
    oBody.TryGetValue<string>('id'    , cId);
    oBody.TryGetValue<string>('status', cStat);
    oBody.TryGetValue<string>('beschr', cBeschr);
 
    if (Empty(cId)) then begin
        result := '{"error":"Feld ''id'' fehlt"}';
        exit;
    end;
 
    if (not DB_LSeek(oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId))) then begin
        result := '{"error":"not found"}';
        exit;
    end;
 
    xTicket := qSqlRead('Y00CXXXXBD', oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId));
    try
        if (not Empty(cStat))  then xTicket.qSet('ti_status'  , cStat);
        if (not Empty(cBeschr)) then xTicket.qSet('ti_beschr'  , cBeschr);
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(UPDATE_RECORD);
    finally
        qSqlFree(xTicket);
    end;
 
    result := '{"status":"updated"}';
end;
 
//------------------------------------------------------------------------------
// DELETE /tickets/v1?id=... - Ticket schliessen (Soft-Delete via Status=9)
//------------------------------------------------------------------------------
 
function Delete(oBody: TJSONObject; oParams: TStrings): string;
var xTicket: TqSQL;
    cId    : string;
begin
    cId := oParams.Values['id'];
    if (Empty(cId)) then begin
        result := '{"error":"Parameter ''id'' fehlt"}';
        exit;
    end;
 
    if (not DB_LSeek(oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId))) then begin
        result := '{"error":"not found"}';
        exit;
    end;
 
    xTicket := qSqlRead('Y00CXXXXBE', oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId));
    try
        xTicket.qSet('ti_status'  , '9');
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(UPDATE_RECORD);
    finally
        qSqlFree(xTicket);
    end;
 
    result := '{"status":"closed"}';
end;
</syntaxhighlight>
 
==Aufruf mit curl==
 
Liste aller offenen Tickets:
 
curl -H "apikey: [API-KEY]" https://api.meinserver.de/tickets/v1
 
Einzelnes Ticket:
 
curl -H "apikey: [API-KEY]" "https://api.meinserver.de/tickets/v1?id=abc-123"
 
Neues Ticket anlegen:
 
curl -X POST -H "apikey: [API-KEY]" -H "Content-Type: application/json" ^
      -d "{\"betreff\":\"Drucker offline\",\"beschr\":\"Etage 2, Raum 23\"}" ^
      https://api.meinserver.de/tickets/v1
 
Ticket aktualisieren:
 
curl -X PUT -H "apikey: [API-KEY]" -H "Content-Type: application/json" ^
      -d "{\"id\":\"abc-123\",\"status\":\"2\"}" ^
      https://api.meinserver.de/tickets/v1
 
Ticket schliessen:
 
curl -X DELETE -H "apikey: [API-KEY]" "https://api.meinserver.de/tickets/v1?id=abc-123"
 
==Aufruf aus PHP==
 
<syntaxhighlight lang="php" line>
<?php
$apikey = '[API-KEY]';
$base  = 'https://api.meinserver.de/tickets/v1';
 
function rest($method, $url, $apikey, $body = null) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL          , $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST , $method);
    $headers = ['apikey: ' . $apikey];
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $res = curl_exec($ch);
    curl_close($ch);
    return json_decode($res, true);
}
 
// Neues Ticket anlegen
$neu = rest('POST', $base, $apikey, [
    'betreff' => 'Drucker offline',
    'beschr'  => 'Etage 2, Raum 23'
]);
$id = $neu['id'];
 
// Status aktualisieren
rest('PUT', $base, $apikey, ['id' => $id, 'status' => '2']);
 
// Liste auslesen
$alle = rest('GET', $base, $apikey);
foreach ($alle as $t) {
    echo $t['nr'] . ' - ' . $t['betreff'] . PHP_EOL;
}
?>
</syntaxhighlight>
 
==Was zeigt das Beispiel?==
 
* Saubere Trennung der CRUD-Methoden in einem Endpunkt.
* Verwendung des JSON-Body fuer komplexere Eingangsdaten (POST, PUT).
* Verwendung von Query-Parametern fuer einfache Werte (GET, DELETE).
* Soft-Delete ueber Status-Aenderung statt physischer Loeschung.
* Eindeutige Audit-UIDs (''Y00CXXXXxx'') fuer jeden DB-Zugriff zur Nachvollziehbarkeit.
* Host-gebundener Zugang als zweite Sicherheitsebene neben dem API-Key.

Version vom 19. Mai 2026, 06:45 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


Beispiel 2: Datensatz anlegen mit JSON-Body

Dieses Beispiel zeigt einen Endpunkt mit allen vier CRUD-Methoden (GET, POST, PUT, DELETE). Es geht um Tickets eines externen Servicedesks, der Tickets ueber den OBS REST-Server in OBS einliefern, abrufen, aktualisieren und schliessen kann.

Einrichtung in OBS

  • Server-Profil: Standard-TLS-Profil Public-API, Bindung 0.0.0.0:443
  • Zugang: Servicedesk-X
    • API-Key: zufaellig generiert
    • Host: servicedesk.kunde.de (DNS-gebunden, IP-Zugriff wird abgelehnt)
    • JWT: nicht aktiv
  • Endpunkt: tickets/v1, Profil Public-API
  • Berechtigung: Zugang Servicedesk-X fuer Endpunkt tickets/v1 freigeschaltet

Endpunkt-Skript tickets/v1

//------------------------------------------------------------------------------
// Hilfsfunktion: einzelnes Ticket als JSON-Objekt aufbauen
//------------------------------------------------------------------------------

function _TicketAsJSON(qTicket: TxFQuery): TJSONObject;
begin
    result := TJSONObject.Create();
    result.AddPair('id'        , qTicket.A2UID());
    result.AddPair('nr'        , qTicket.A2C('ti_nr'));
    result.AddPair('betreff'   , qTicket.A2C('ti_betreff'));
    result.AddPair('status'    , qTicket.A2C('ti_status'));
    result.AddPair('beschr'    , qTicket.A2C('ti_beschr'));
    result.AddPair('aenderung' , DTToSQL(qTicket.A2D('ti_aend_dat')));
end;

//------------------------------------------------------------------------------
// GET   /tickets/v1?id=...   - einzelnes Ticket
// GET   /tickets/v1          - alle offenen Tickets
//------------------------------------------------------------------------------

function Get(oBody: TJSONObject; oParams: TStrings): string;
var cSql  : string;
    qData : TxFQuery;
    oArr  : TJSONArray;
    cId   : string;
begin
    cId := oParams.Values['id'];

    if (not Empty(cId)) then begin
        cSql := 'SELECT * FROM tickets WHERE sys_uid = ' + DB_SQLVal(cId);
        if (DB_SOpen('Y00CXXXXBA', oDB, cSql, qData)) then begin
            result := _TicketAsJSON(qData).ToJSON();
        end else begin
            result := '{"error":"not found"}';
        end;
        DB_Close(qData);
    end else begin
        oArr := TJSONArray.Create();
        try
            cSql := 'SELECT * FROM tickets WHERE ti_status <> "9" ORDER BY ti_aend_dat DESC';
            if (DB_SOpen('Y00CXXXXBB', oDB, cSql, qData)) then begin
                while (not qData.EoF) do begin
                    oArr.Add(_TicketAsJSON(qData));
                    qData.Next();
                end;
            end;
            DB_Close(qData);

            result := oArr.ToJSON();
        finally
            MyFreeAndNil(oArr);
        end;
    end;
end;

//------------------------------------------------------------------------------
// POST  /tickets/v1          - neues Ticket anlegen
// Body: { "betreff":"...", "beschr":"..." }
//------------------------------------------------------------------------------

function Post(oBody: TJSONObject; oParams: TStrings): string;
var xTicket : TqSQL;
    cId     : string;
    cBetreff: string;
    cBeschr : string;
    oRes    : TJSONObject;
begin
    if (not Assigned(oBody)) then begin
        result := '{"error":"JSON-Body erforderlich"}';
        exit;
    end;

    cBetreff := '';
    cBeschr  := '';
    oBody.TryGetValue<string>('betreff', cBetreff);
    oBody.TryGetValue<string>('beschr' , cBeschr);

    if (Empty(cBetreff)) then begin
        result := '{"error":"Feld ''betreff'' fehlt"}';
        exit;
    end;

    cId := GetNewId(oDB);

    xTicket := qSqlInit('Y00CXXXXBC', oDB, 'tickets');
    xTicket.lNoSysUID := True;
    try
        xTicket.qSet('sys_uid'    , cId);
        xTicket.qSet('ti_nr'      , DB_NeuNum(oDB, 'tickets', 'ti_nr', NEUNUM_HOLE, '', '', 1, 999999, '0'));
        xTicket.qSet('ti_betreff' , cBetreff);
        xTicket.qSet('ti_beschr'  , cBeschr);
        xTicket.qSet('ti_status'  , '1');
        xTicket.qSet('ti_anl_dat' , Now());
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(NEW_RECORD);
    finally
        qSqlFree(xTicket);
    end;

    oRes := TJSONObject.Create();
    try
        oRes.AddPair('id'    , cId);
        oRes.AddPair('status', 'created');
        result := oRes.ToJSON();
    finally
        MyFreeAndNil(oRes);
    end;
end;

//------------------------------------------------------------------------------
// PUT   /tickets/v1          - Ticket aktualisieren
// Body: { "id":"...", "status":"...", "beschr":"..." }
//------------------------------------------------------------------------------

function Put(oBody: TJSONObject; oParams: TStrings): string;
var xTicket: TqSQL;
    cId    : string;
    cStat  : string;
    cBeschr: string;
begin
    if (not Assigned(oBody)) then begin
        result := '{"error":"JSON-Body erforderlich"}';
        exit;
    end;

    cId     := '';
    cStat   := '';
    cBeschr := '';
    oBody.TryGetValue<string>('id'    , cId);
    oBody.TryGetValue<string>('status', cStat);
    oBody.TryGetValue<string>('beschr', cBeschr);

    if (Empty(cId)) then begin
        result := '{"error":"Feld ''id'' fehlt"}';
        exit;
    end;

    if (not DB_LSeek(oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId))) then begin
        result := '{"error":"not found"}';
        exit;
    end;

    xTicket := qSqlRead('Y00CXXXXBD', oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId));
    try
        if (not Empty(cStat))   then xTicket.qSet('ti_status'  , cStat);
        if (not Empty(cBeschr)) then xTicket.qSet('ti_beschr'  , cBeschr);
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(UPDATE_RECORD);
    finally
        qSqlFree(xTicket);
    end;

    result := '{"status":"updated"}';
end;

//------------------------------------------------------------------------------
// DELETE /tickets/v1?id=...  - Ticket schliessen (Soft-Delete via Status=9)
//------------------------------------------------------------------------------

function Delete(oBody: TJSONObject; oParams: TStrings): string;
var xTicket: TqSQL;
    cId    : string;
begin
    cId := oParams.Values['id'];
    if (Empty(cId)) then begin
        result := '{"error":"Parameter ''id'' fehlt"}';
        exit;
    end;

    if (not DB_LSeek(oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId))) then begin
        result := '{"error":"not found"}';
        exit;
    end;

    xTicket := qSqlRead('Y00CXXXXBE', oDB, 'tickets', 'sys_uid = ' + DB_SQLVal(cId));
    try
        xTicket.qSet('ti_status'  , '9');
        xTicket.qSet('ti_aend_dat', Now());
        xTicket.SaveData(UPDATE_RECORD);
    finally
        qSqlFree(xTicket);
    end;

    result := '{"status":"closed"}';
end;

Aufruf mit curl

Liste aller offenen Tickets:

curl -H "apikey: [API-KEY]" https://api.meinserver.de/tickets/v1

Einzelnes Ticket:

curl -H "apikey: [API-KEY]" "https://api.meinserver.de/tickets/v1?id=abc-123"

Neues Ticket anlegen:

curl -X POST -H "apikey: [API-KEY]" -H "Content-Type: application/json" ^
     -d "{\"betreff\":\"Drucker offline\",\"beschr\":\"Etage 2, Raum 23\"}" ^
     https://api.meinserver.de/tickets/v1

Ticket aktualisieren:

curl -X PUT -H "apikey: [API-KEY]" -H "Content-Type: application/json" ^
     -d "{\"id\":\"abc-123\",\"status\":\"2\"}" ^
     https://api.meinserver.de/tickets/v1

Ticket schliessen:

curl -X DELETE -H "apikey: [API-KEY]" "https://api.meinserver.de/tickets/v1?id=abc-123"

Aufruf aus PHP

<?php
$apikey = '[API-KEY]';
$base   = 'https://api.meinserver.de/tickets/v1';

function rest($method, $url, $apikey, $body = null) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL           , $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST , $method);
    $headers = ['apikey: ' . $apikey];
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $res = curl_exec($ch);
    curl_close($ch);
    return json_decode($res, true);
}

// Neues Ticket anlegen
$neu = rest('POST', $base, $apikey, [
    'betreff' => 'Drucker offline',
    'beschr'  => 'Etage 2, Raum 23'
]);
$id = $neu['id'];

// Status aktualisieren
rest('PUT', $base, $apikey, ['id' => $id, 'status' => '2']);

// Liste auslesen
$alle = rest('GET', $base, $apikey);
foreach ($alle as $t) {
    echo $t['nr'] . ' - ' . $t['betreff'] . PHP_EOL;
}
?>

Was zeigt das Beispiel?

  • Saubere Trennung der CRUD-Methoden in einem Endpunkt.
  • Verwendung des JSON-Body fuer komplexere Eingangsdaten (POST, PUT).
  • Verwendung von Query-Parametern fuer einfache Werte (GET, DELETE).
  • Soft-Delete ueber Status-Aenderung statt physischer Loeschung.
  • Eindeutige Audit-UIDs (Y00CXXXXxx) fuer jeden DB-Zugriff zur Nachvollziehbarkeit.
  • Host-gebundener Zugang als zweite Sicherheitsebene neben dem API-Key.