OBS/Kostenpflichtige Module/RESTServer/Beispiel3: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Böhrer (Diskussion | Beiträge) (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…“) |
Keine Bearbeitungszusammenfassung |
||
| (Eine dazwischenliegende Version desselben Benutzers wird nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
{{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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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. | |||
Aktuelle Version vom 19. Mai 2026, 06:49 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
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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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(oParams: TStrings; oBody: TJSONObject): 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.