Dieser Abschnitt enthält Information zu den Schnittstellen in RELion ONE.
Das ist eine für den Ausdruck optimierte Ansicht des gesamten Kapitels inkl. Unterseiten. Druckvorgang starten.
Schnittstellen
- 1: Schnittstellen - Installation und Einrichtung
- 2: URA (Universal REST API)
- 2.1: Request Aufbau
- 2.2: Einrichtung und Konfiguration Universal REST API
- 2.3: GUI-Tool
- 2.4: Beispiele
- 2.5:
1 - Schnittstellen - Installation und Einrichtung
Schnittstellen - Installation und Einrichtung
Überblick und Zuständigkeiten
flowchart TD classDef Aareon_blue fill:#051163,stroke:#051163,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Bright_blue fill:#086DFB,stroke:#086DFB,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Sand fill:#F7F3F0,stroke:#F7F3F0,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Stone fill:#EBE3DC,stroke:#EBE3DC,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Coral fill:#FF7F62,stroke:#FF7F62,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Peach fill:#FFD8CA,stroke:#FFD8CA,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Green fill:#50B214,stroke:#50B214,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Light_green fill:#B9E99C,stroke:#B9E99C,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Baby_blue fill:#A4CBFF,stroke:#A4CBFF,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Burgundy fill:#550000,stroke:#550000,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Dark_green fill:#2F630E,stroke:#2F630E,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif E[Microsoft Entra ID]:::Coral RP[RELion<br>Produktiv]:::Green RS[RELion<br>Sandbox]:::Green NSTP[Business Central Dienst<br>Produktiv]:::Bright_blue NSTS[Business Central Dienst<br>Sandbox]:::Bright_blue subgraph SGE["`**Kunde - Entra-Admin**`"] E end class SGE Peach subgraph SGR["`**Kunde - Super-User**`"] E --> RP E --> RS end class SGR Light_green subgraph SGNST["`**Aareon RELion - Dev-Ops**`"] RP --> NSTP RS --> NSTS end class SGNST Aareon_blue
2 - URA (Universal REST API)
Mit der Universal REST API bietet RELion eine Möglichkeit, auf jede Tabelle über einen REST API Aufruf zuzugreifen. Der schematische Aufbau des Calls ist für jede Tabelle identisch und eine Ausführung der RELion Business Logik gewährleistet. Es stehen Standardfunktionen für die Interaktion mit RELion zur Verfügung:
- Einfügen
- Ändern
- Kombiniertes Einfügen und Ändern
- Löschen eines Datensatzes
- Lesen (einzelner Datensatz oder mehrere Daten)
- Ändern des Primärschlüssels eines Datensatzes
Weitere ergänzende Funktionen sind:
- der Bulk Modus
- die Verwendung von verschiedenen Konfigurationen
Universal REST API in sechs Schritten
- Identifizierung der RELion Tabelle in der GUI
- BC Tabellen Nummer und Feldnummern heraussuchen
- Erstellen des REST Requests, bestehend aus oa. Nummern und dem Payload
- Senden des Requests an die universal REST API
- Verarbeitung des Request durch RELion
- Rückmeldung der Verarbeitung
a. Verarbeitung war fehlerfrei, Rückmeldung mit dem angelegten oder geänderten Datensatz
b. Verarbeitung lief auf einen Fehler, Rückmeldung des Fehlers in Klartext
Die Business Logik in BC basiert stark auf der Reihenfolge, wie der Anwender Felder in einer Tabelle füllt, auch diesen Umstand berücksichtig die REST API, die Reihenfolge der Felder im JSON Body entsprechen der Reihenfolge, indem die API die Daten in die RELion Tabelle schreibt. Eine Umstellung ist jederzeit durch eine Umsortierung der Felder im Request möglich. Mit weiteren Parametern kann die REST API auch komplexe Einfügeoperationen in RELion abbilden (z. B. kombinierte Einfüge und Update Anweisungen oder das Überspringen von Validierungen).
Anders als bei SQL-Abfragen auf BC-Tabellen, kann die universal REST API auch die Flow Fields einer Tabelle zurückgeben. Dies bezieht sich auf Tabellenfelder, berechnete Felder, welche nur auf den Pages oder in Infoboxen vorhanden sind, berücksichtigt die API nicht. Durch die mögliche Verwendung von verschiedenen Konfigurationen pro REST API Aufruf, kann die API, je nach Anwendungszweck, diese Daten in die Antwort aufnehmen oder nicht.
Darüber hinaus sind auch gebündelte Operationen möglich. In einem REST API Aufruf sind dann mehrere Datensätze zum Einfügen oder Ändern enthalten, dies spart dann die Zeit für dem Aufbau der Webserviceverbindung pro Datensatz und kann die Laufzeit bei einer großen Menge an Daten senken. Auch diese Bulk-Übertragungen haben die identischen Möglichkeiten eines Aufrufes pro Datensatz.
In dem Beispiel wird der Übertrag eines Debitors aus einem Fremdsystem nach RELion dargestellt, vor allem die Ableitung aus der RELion Tabelle und den daraus resultierenden Request.
Das Auslösen der Kommunikation und der Abgleich der Tabellen und Felder ist nicht Bestandteil dieser Dokumentation.
2.1 - Request Aufbau
Aufbau eines Request
Base URL
Die Requests sind an die Adresse der URA zu senden. Diese ist
OnPrem:
https://{{base URL}}:{{port}}/{{serverinstance}}/api/aareon/universalapi/v1.0/companies({{Company-Id}})/universalRequests?$expand=entitySet
URA GET
Die GET-Methode zeigt lediglich die Verfügbarkeit der API an, die Universal REST API steht für alle Mandaten zur Verfügung und benötigt zur Identifikation des Mandanten noch die Mandanten ID in der URL. Die Prüfung, ob die API verfügbar ist benötigt diesen Zusatz nicht.
Die Adresse für die GET-Methode setzt sich aus vier Komponenten zusammen:
- Webadresse des Servicetiers
- Port der BC OData Services
- BC Dienstnamen
- restliche Pfad: /api/aareon/universalapi/v1.0/$metadata
Eine vollständige Adresse für einen GET Aufruf wäre somit:
http://MeinServer:14048/MeinServiceTier/api/aareon/universalapi/v1.0/$metadata
Zurück kommt ein XML-File mit allen aktiven API’s:
URA POST
Für einen Request wird immer ein POST-Request an den Endpunkt geschickt. Dieser enthält einen Body mit einem JSON. Das JSON besteht aus zwei Teilen, der Definition der Tabelle und den Daten, welche auf die Tabelle anzuwenden sind. Die verschiedenen Ausprägungen des Bodys sind in JSON Body beschrieben.
Beispiel:
Lesen aus der Tabelle mit der ID 5050. Es werden die Felder mit der ID 1 und ID 2. Die ersten 620 Datensätze werden übersprungen und dann werden 100 Datensätze geliefert.
Request:
{
"tableNo": "5050",
"operation": "READ",
"top": "100",
"skip":"620",
"entitySet": [
{
"subOperation": "Done",
"responseFields": "1|2"
}
]
}
Response:
{
"@odata.etag": "W/\"JzIwOzE2Mjg3NjY1MDI0ODQ3NzE5ODM0MTswMDsn\"",
"headerId": "8804c1b9-444c-42cb-809c-6ea49e0dc91e",
"lineNo": "10000",
"fieldNo": 0,
"filter": false,
"dimensionSetId": false,
"dimensionSetIdMutation": 0,
"dimension": false,
"dimensionCode": "",
"validate": false,
"value": "",
"subOperation": "DONE",
"resetFilter": false,
"singleCommit": false,
"responseFields": "1|2",
"totalCount": 625,
"skippedRows": 620,
"numberOfRows": 625,
"moreRows": false,
"done": false,
"countOfReturnRows": 5,
"ResponseJson2": "eyJEYXRhIjpbeyJOby4iOiJLMDEwMDA0IiwiTmFtZSI6IkRldXRzY2hlIFRlbGVjb20gQUcifSx7Ik5vLiI6IkswMTAwMDUiLCJOYW1lIjoiRGViaXRvIFJlc2VzIn0seyJOby4iOiJLMDEwMDA2IiwiTmFtZSI6IlRydWRlbCBXZXJlcyJ9LHsiTm8uIjoiSzAxMDAwNyIsIk5hbWUiOiJEZWxvcmVzIDEwMDAifSx7Ik5vLiI6IkxFRVIiLCJOYW1lIjoiTGVlciJ9XX0="
}
Im Feld ResponseJson2 gibt die REST API den angelegten Datensatz in Base64 Kodierung zurück. Encodiert ist es JSON. Sie können die Anzahl der Felder, welche die API zurückgibt, über den Parameter responseFields einschränken. Ohne den Eintrag gibt die API immer alle Felder aus der Tabelle zurück.
Decodiert steht nun da:
{
"Data": [
{
"No.": "K010004",
"Name": "Deutsche Telecom AG"
},
{
"No.": "K010005",
"Name": "Debito Reses"
},
{
"No.": "K010006",
"Name": "Trudel Weres"
},
{
"No.": "K010007",
"Name": "Delores 1000"
},
{
"No.": "LEER",
"Name": "Leer"
}
]
}
Die Prüfung der Datenfelder erfolgt durch Business Central. Bei nicht passenden Kombinationen (z. B. Text in ein Zahlenfeld zu schreiben oder nicht vorhandene Werte in verbundenen Tabellen), beendet die API den Request mit einer Fehlermeldung.
URA JSON Body
Json Header
Der Body besteht aus einem “Kopf”, dem universalRequest und dann einen Array von zusammenhängenden Befehlsblöcken, dem entitySet. Eine Suboperation schließt jeweils einen Befehlsblock logisch ab.
Die Befehlsblöcke setzen sich aus verschiedenen Attributen zusammen, je nach Verwendungszweck des Blockes. Die API arbeitet die Blöcke sequenziell ab, die Reihenfolge legt somit auch die Filter und Validierungsreihenfolge in BC fest.
Die BC Tabelle ist pro Aufruf konstant, alle Operationen führt die API nur auf dieser Tabelle durch, Kopf und Zeilen Strukturen benötigen zwei API aufrufe. Die benötigten Daten liefert die API nach Abschluss der gesamten Operation zurück.
Die API liefert als Antwort nochmals den gesamten Aufruf als Body mit, dies ist technisch begründet und kann nicht unterbunden werden. In jedem Suboperation Block ist das Attribut response vorhanden, in diesem Attribut kann die API den neuen / geänderten Datensatz nach der jeweiligen Operation zurückliefern, je nach Suboperation und Anwendungsfall.
Das Feld response ist BASE64 codiert und enthält ein JSON mit den Daten der Tabelle, ein Filter kann die zurückgegebenen Felder einschränken.
Der Aufbau des entitySet Bereiches ist variabel, um die verschiedensten Konstellationen in BC abzubilden, die drei am meisten genutzten Anwendungsbereiche sind dabei:
- Einzelanweisung, ein Datensatz ohne komplexe Trigger und Validierungen über die API einfügen oder verändern.
- Kombinierte Anweisung, INSERT und UPDATE in einem Aufruf. Komplexe Trigger und Validierungen über die API. simulieren, beispielsweise setzt der Inserttrigger beim Einfügen eines Debitors die Debitorennummer und einige Defaultwerte, diese können dann im folgenden UPDATE Teil, innerhalb eines Aufrufes, auf die gewünschten Werte angepasst werden.
- Einfügen einer großen Datenmenge mit wenigen Aufrufen (BULK – Modus). Ziel ist es, die Minimierung des Overheads für die Kommunikation über die API. In einem Aufruf sind 30 bis 50 Datensätze enthalten, welche die API in einer Datenbank Transaktion verarbeitet.
Es gibt folgede Parameter:
-
tableNo - Tabellen Nummer
Das Attribut tableNo spezifiert die Tabellen in BC auf welche die Operation angewendet werden soll. Es ist die Nummer der Tabelle aus BC anzugeben. Diese ist abrufbar unter anderem über den Punkt Info zu der Seite. -
operation - Funktionen auf BC Tabellen
Es stehen diese Funktionen zur Verfügung: Einer dieser Operationen ist in der Ebene universalRequest anzugeben, sie definiert den übergeordneten Anwendungsfall. Reicht eine Operation pro Webrequest, so ist dieser mit der subOperation DONE in der Ebene entitySet zu bestätigen. Verschiedene Anwendungsfälle, wie ein INSERT gefolgt von einem UPDATE oder BULK Operationen, lassen sich mit den subOperationen in der der Ebene entitySet abbilden.- INSERT
Mit der INSERT – Operation fügt die API die im Bereich entitySet definierten Daten der definierten BC Tabelle hinzu, ob der BC Insert Trigger dabei zur Ausführung kommt, bestimmt ein weiterer Parameter. Die Reihenfolge in der die API die einzelnen Felder in die BC Tabelle einfügt, ist durch die Reihenfolge der Daten in entitySet Bereich festgelegt, über diesen Mechanismus sind verschiedene Feldvalidierungsreihenfolgen abbildbar. - UPDATE
Mithilfe der UPDATE – Operation, kann die API Daten eines bestehenden Datensatzes verändern. Filterkriterien um den Datensatz zu bestimmen sind im entitySet Bereich zu definieren. - DELETE
Der DELETE-Operator benötig einen Filter, der nur einen Datensatz als Ergebnis liefert, bei mehr als ein Datensatz pro Operation liefert die API einen Fehler, damit sind Löschvorgange auf einen ganzen Bereich in einer Operation ausgeschlossen. - RENAME
BC unterscheidet zwischen einer Änderung von Daten und einem Umbenennen von Daten, bei der Änderung sind keine Felder des Primärschlüssel, den eindeutigen Identifier des Datensatzes in der Tabelle, betroffen. Ein Primärschlüssel (PS) kann mehrere Felder einschließen, ist nur ein Feld von einer Änderung betroffen, so geht BC und damit auch die API von einem Rename aus. - READ
Die API kann zusätzlich zu den Schreiboperationen auch Datensätze aus Tabellen zurückliefern. Die READ-Operation liefert je nach mitgegeben Filter 0 bis alle Datensätze einer Tabelle zurück. Die maximale Anzahl der zurückgelieferten Daten bestimmt der Wert numberOfEntitiesToRead in der Konfiguration, im Standard 100. - READLAST
Die API kann zusätzlich zu den Schreiboperationen auch Datensätze aus Tabellen zurückliefern. Die READLAST Operation liefert je nach mitgegeben Filter keinen oder den letzten Datensatz passend zu dem Filter aus einer Tabelle zurück. Der Request ist immer mit der “subOperation”:“DONE” abzuschließen. Mehrfache Operationen sind nicht zulässig.
- INSERT
-
runTrigger – Attribut
BC Tabellen haben für jede Art der Änderung an Tabellen Trigger, welche Code ausführen können. Dieses Attribut steuert, ob die API den jeweiligen Triggers ausführt (true) oder nicht (false). Der Insert-Trigger auf der Debitorentabelle (18) führt verschiedene Prüfungen durch, unter anderem prüft er, ob eine Debitorennummer vorhanden ist, sollte dies nicht der Fall sein, holt sich der Trigger diese aus den Nummernserien. -
setupCode – Attribut
Ohne die Angabe oder mit der Angabe eines nicht definierten setupCode’s verwendet die API immer die Konfiguration mit leeren Code Feld. -
entitySet – Attribute
Attribute teilen sich in MUSS und KANN Attribute auf, fehlt ein MUSS Attribut quittiert dies die API mit einem Fehler. KANN Attribute haben Standardwerte, diese sind in dem entsprechenden Kapitel erläutert. Die verschiedenen Attribute sind sechs Gruppen zuzuordnen und nur in diesen Gruppen zu verwenden:- Abschluss einer Operation oder Suboperation
- Einfügen von Daten
- Ändern von Daten
- Löschen von Daten
- Lesen von Daten
- obsolete Attribute
-
Operation und Suboperation
Jeder Request ist mit einer Suboperation abzuschließen, diese löst die Verarbeitung der Daten in der API aus. Ein Aufruf mit Blöcken ohne eine Suboperation am Ende hat keine Auswirkung auf das System, RELion speichert den Aufruf ohne diesen auszuführen.Die Anordnung der Blöcke entspricht der Verarbeitungsreihenfolge, dies hat direkte Auswirkung auf die Validierungsreihenfolge in RELion. Das Einfügen einer Objektnummer ohne vorheriges Füllen des Eigentümer/Mieter Kennzeichens löst beispielsweise eine Fehlermeldung aus. Oft sind die Feldreihendfolgen auf den BC Pages eine Orientierung für die korrekte Reihenfolge der Felder für die API.
Auch Suboperationen beziehen sich auf die im tableNo Attribut definierte Tabelle, es ist nicht möglich Daten durch Suboperationen in unterschiedliche Tabellen zu schreiben.
Die Anwendung von Suboperationen ist in drei Bereich aufzuteilen:
- Insert – Update Aufrufe, um Daten, welche RELion bei der Ausführung des Insert Triggers durch Default Werte ersetzt mit einem anschließenden Update Teil in einem Aufruf einzufügen.
- Insert - …… -Insert (BULK) Einfügeoperationen, ein Aufruf schreibt mehrere Datensätze in die Datenbank.
- Update - …… - Update Änderungsoperationen, ein Aufruf ändert verschiedene Datensätze.
Der kombinierte Aufruf von Insert – Update vereinfacht das Einfügen von Daten, wenn der RELion Insert Trigger, beispielsweise die Nummer aus der Nummernserie holt und dann weitere Default Werte setzt, aber die Daten genau diese Default Werte ändern. Hier sind dann nicht mehr zwei Aufrufe mit der Verarbeitung der Antwort nötig. Die API behält den neu angelegten Datensatz im Fokus und führt dann die gewünschte Änderung nach dem Einfügen der Daten in die Datenbank in einem API Aufruf durch.
Die BULK Bereiche Insert und Update, dazu gehört auch eine mehrfach kombinierte Insert – Update Anweisung, ist vor allem für große Datenmengen konzipiert. Der Overhead für den Aufbau und Abbau der Verbindung fällt nur einmal für die Anzahl der gemeinsam übertragenden Daten an, nicht für jede Operation.
-
Gültige Attribute für den Suboperationsbereich
Vier Attribute sind zulässig:"subOperation": "DONE….", "resetFilter": false, "singleCommit": false, "responseFields": "1|2"
Das Attribut subOperation ist zwingend und beschreibt die Vorgehensweise mit welcher die API die vorher übergebenen Blöcke verarbeitet. Die möglichen Ausprägungen sind:
-
DONE
Schließt die im Attribut operation definierte Operation ab und füllt das Attribut response. DONE beachtet die Option responseFields, alle anderen Optionen bleiben unbeachtet. Die Operationen READ sind immer mit einem DONE abzuschließen, ebenso bei Aufrufen mit einer Operation. -
INSERT
Mittels INSERT fügt die API einen Datensatz mit den übergebenen Werten in die spezifizierte Tabelle ein. Ein INSERT erstellt keinen Inhalt im Attribut response. Für weitere Operationen speichert die API eine Referenz auf den neuen Datensatz. Diese Suboperation macht keinen Gebrauch von weitere Attributen. Beispiel für zwei Inserts, einmal der Wert 10 und einmal der Wert 20 in das Feld 100:{ "tableNo": "5358944", "operation": "INSERT", "runTrigger": true, "entitySet": [ { "fieldNo": 100, "validate": true, "value": "10" }, { "subOperation": "INSERT" }, { "fieldNo": 100, "validate": true, "value": "20" }, { "subOperation": "INSERT" } ] }
-
INSERT_RESPONSE
Zusätzlich zum Einfügen der Daten in die Datenbank, erstellt ein INSERT_RESPONSE auch das Rückgabe-JSON in dem Attribut response. Für jeden Datensatz erstellt die API den Rückgabewert in dem zugehörigen Suboperationsbereich. Mit dem Attribut resonseFields lassen sich die Felder in dem Rückgabewert einschränken. Das gleiche Beispiel wie im Beispiel Suboperation INSERT, nur diesmal mit INSERT_RESPONSE:{ "tableNo": "5358944", "operation": "INSERT", "runTrigger": true, "entitySet": [ { "fieldNo": 100, "validate": true, "value": "10" }, { "subOperation": "INSERT_RESPONSE", "responseFields": "1|100" }, { "fieldNo": 100, "validate": true, "value": "20" }, { "responseFields": "1|100", "subOperation": "INSERT_RESPONSE" } ] }
In der Antwort ist aber nun auch das ResponseJson2 wie beim READ gefüllt.
-
UPDATE
Ein UPDATE ändert einen bestehenden Datensatz, Anpassungen von mehreren Datensätzen in einer Suboperation, über einen Filter, der mehr als einen Datensatz liefert, unterstütz die API nicht. Eine Update Anweisung, ohne vorheriges Einfügen eines Datensatzes, benötig einen Filter zur Identifizierung. Ein Filter besteht aus dem Tripel von Attributen fieldNo, value und filter, diese sind vor der Suboperation zu definieren. Das Attribut value nimmt Werte eines Standard BC Filters, wie “>10” oder “1|2”, entgegen. Bei der Suboperation UPDATE erzeugt die API keine Antwort wie auch beim INSERT.Bei kombinierten Anweisungen behält die API den Fokus auf dem vorherigen Datensatz. Damit ist es möglich weitere Anweisungen auf dem identischen Datensatz auszuführen ohne einen neuen Filter zu definieren. Um Updates auf verschiedenen Datensätzen kombiniert durchzuführen, setzt das Attribut resetfilter den Filter nach der Suboperation zurück.
-
UPDATE_RESPONSE
Die Vorbedingungen für die Suboperation UPDATE_RESPONSE sind identisch mit den aus SubOperation UPDATE, im Unterschied zum UPDATE erzeugt die API beim UPDATE_RESONSE eine Antwort im response Attribut.
Mittels dieser Operation sind Konstellationen wie Einfügen und Ändern von Datensätzen mit Rückmeldung möglich, auch mehrfache Updates mit einem UPDATE_RESPONSE am Ende liefern dann den endgültigen Datensatz zurück, der Overhead eine Rückmeldung für jede Suboperation zu erstellen und auszuwerten entfällt. Beispiel:{ "tableNo": 5358944", "operation": "INSERT", "runTrigger": true, "setupCode": "", "entitySet": [ { "fieldNo": 100, "validate": true, "value": "10" }, { "fieldNo": 2, "validate": true, "value": "99" }, { "subOperation": "INSERT" }, { "fieldNo": 3, "validate": true, "value": "99" }, { "subOperation": "UPDATE" }, { "fieldNo": 2, "validate": true, "value": "199" }, { "responseFields": "100|2|3", "subOperation": "UPDATE_RESPONSE" } ] }
Die API fügt einen neuen Datensatz in die Tabelle ein, dabei ist der Wert des Feldes 2 = 99 und das Feld 3 ist leer. Im zweiten Schritt erfolgt ein Update auf den eingefügten Datensatz, da die Definition eines neuen Filters für die Update Operation fehlt. Im letzten Schritt überschreibt die API das Feld 2 mit dem Wert 199, die Operation erfolgt immer noch auf dem eingefügten Datensatz. Schließlich erzeugt die Suboperation UPDATE_RESPONSE eine Antwort mit den Feldern 100,2 und 3.
-
RENAME
Analog zu der Operation RENAME, ist die serielle Verarbeitung mehrere Umbenennungen über die Suboperation RENAME möglich.{ "tableNo": "5358944", "operation": "RENAME", "runTrigger": true, "setupCode": "", "entitySet": [ { "fieldNo": 1, "filter": true, "value": "{53cd97b6-cc44-40ce-8f6b-4a8167f9422c}" }, { "fieldNo": 1, "validate": true, "value": "{53cd97b6-cc44-40ce-8f6b-4a8167f9422d}" }, { "responseFields": "1|2|100", "subOperation": "RENAME" }, { "fieldNo": 1, "filter": true, "value": "{68cd97b6-cc44-40ce-8f6b-4a8167f9422c}" }, { "fieldNo": 1, "validate": true, "value": "{68cd97b6-cc44-40ce-8f6b-4a8167f9422d}" }, { "responseFields": "1|2|100", "subOperation": "RENAME" } ] }
Die API berücksichtigt Tablerelations, somit ist zu berücksichtigen, dass mehrfach Umbenennungen durchaus in einen Timeout der API laufen können.
-
READ
Die Suboperation kann zur Anwendung kommen, wenn zwei oder mehr Datensätze in einem Request aus BC zu lesen sind und dies nicht über einen Filter möglich ist oder das aufrufende System keine mehrfachen Datensätze im responseJson Attribut verarbeiten kann. -
DELETE
Analog zu der RENAME Suboperation, kann der DELETE Suboperator mehrere Datensätze in einem REST API Call löschen, pro Operation jedoch nur einen Datensatz. So könnte man Zeilen zu einem spezifischen Kopf löschen. Zuerst die Zeilen per READ auslesen und dann alle Zeilen in ein DELETE Request aufnehmen. Beispiel für das löschen mehrerer Datensätzen in einem Request:{ "tableNo": "5358944", "operation": "DELETE", "runTrigger": true, "setupCode": "", "entitySet": [ { "fieldNo": 1, "filter": true, "value": "{7df044ad-e5a8-4f61-83cc-0014e8837af8}" }, { "subOperation": "DELETE" }, { "fieldNo": 1, "filter": true, "value": "{576044cd-e7a8-4c61-82cc-001cdedd7af8}" }, { "subOperation": "DELETE" } ] }
Die API speichert den Verweis auf den Datensatz, welche bei der Ausführung der Suboperation im Zugriff war. Soll die API auf ein anderer Datensatz mit einem folgenden Bereich zugreifen, so löst "resetFilter": true den Filter auf den Datensatz auf und eine neue Definition eines Filters ist möglich. Das Attribut ist im Standard false und nur bei Bedarf zu füllen.Im Standard ist ein API Aufruf auch eine Transaktion. Dabei schreibt BC alle Änderungen gesammelt am Ende in die Datenbank, tritt ein Fehler bei der Verarbeitung auf, dann speichert BC keine Änderung. Mit dem Attribut “singleCommit”: true ändert die API das Verhalten und schreibt jeden abgeschlossenen Bereich in die Datenbank. Dem Vorteil, jeden Block sofort in der Datenbank zu speichern, stehen eine wesentlich geringere Performance und aufwendigere Aufbereitung der fehlerhaften Daten gegenüber. Bis auf besondere Fälle ist das Standardverhalten ein Aufruf gleich einer Transaktion dem singleCommit vorzuziehen.
Die Fehlerbehandlung bei mehreren Insert Bereichen ist je nach dem Attribut singleCommit anzupassen. Da die Daten mit aktivierten singleCommit bis zum Fehler in der Datenbank vorhanden sind, bei deaktivierten hingegen nicht.
Ohne das Attribut responseFields gibt die Schnittstelle immer alle Felder der Tabelle im response JSON zurück. Um die Anzahl der Felder einzuschränken, nimmt die API im Attribut responseFields einen BC Filterstring mit den Feldnummern der Tabelle auf. Soll im response nur die Felder 3,5,50001 und 5358755 enthalten sein, so ist das Attribut “responseFields”: “3|5|50001|5358755” der Suboperation hinzuzufügen. Jeder Suboperation kann eine unterschiedliche Ausprägung des Attributes zugeordnet sein.
-
2.2 - Einrichtung und Konfiguration Universal REST API
Einrichtung
Um eine sichere Verbindung zwischen den Systemen aufbauen zu können, wird der Standard OpenID Connect verwendet. In Bezug auf Microsoft Dynamics 365 Business Central lautet das Stichwort hier “Service-to-Service” Authentication (S2S): https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/automation-apis-using-s2s-authentication
Somit sind grundsätzlich Tätigkeiten in drei Ebenen nötig.
flowchart TD classDef Aareon_blue fill:#051163,stroke:#051163,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Bright_blue fill:#086DFB,stroke:#086DFB,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Sand fill:#F7F3F0,stroke:#F7F3F0,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Stone fill:#EBE3DC,stroke:#EBE3DC,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Coral fill:#FF7F62,stroke:#FF7F62,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Peach fill:#FFD8CA,stroke:#FFD8CA,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Green fill:#50B214,stroke:#50B214,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Light_green fill:#B9E99C,stroke:#B9E99C,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Baby_blue fill:#A4CBFF,stroke:#A4CBFF,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Burgundy fill:#550000,stroke:#550000,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Dark_green fill:#2F630E,stroke:#2F630E,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif E[Microsoft Entra ID]:::Coral RP[RELion<br>Produktiv]:::Green RS[RELion<br>Sandbox]:::Green NSTP[Business Central Dienst<br>Produktiv]:::Bright_blue NSTS[Business Central Dienst<br>Sandbox]:::Bright_blue subgraph SGE["`**Kunde - Entra-Admin**`"] E end class SGE Peach subgraph SGR["`**Kunde - Super-User**`"] E --> RP E --> RS end class SGR Light_green subgraph SGNST["`**Aareon RELion - Dev-Ops**`"] RP --> NSTP RS --> NSTS end class SGNST Aareon_blue
-
Registrieren Sie in Ihrem Entra ID-Tenant muss durch Ihren Entra-Admin eine zusätzliche Unternehmensanwendung je zugreifendem Programm registriert werden.
-
Beispiel
- Eine Applikation für das RELion Consulting zur Einrichtungskontrolle
- Eine Applikation für das DMS
- Eine Applikation für das Vermietungsportal
- …
-
Die entsprechende Anleitung zum Registrieren der Anwendung finden Sie hier: https://learn.microsoft.com/de-de/dynamics365/business-central/dev-itpro/administration/automation-apis-using-s2s-authentication#task-1-register-a-microsoft-entra-application-for-authentication-to-business-central
- In “Task 1” der Microsoft Dokumentation wird die Anwendung in Ihrem Entra ID Tenant registriert.
- Als API-Berechtigungen werden folgende Dynamics 365 Business Central Anwendungsberechtigungen benötigt
- API.ReadWrite.All
- Automation.ReadWrite.All
- Bitte teilen Sie uns Tenant ID, Client ID und Client Secret (zufallsgeneriertes Passwort, 40 Stellen) für die Applikation zur Einrichtungskontrolle durch das RELion Consulting über einen verschlüsselten Weg mit.
-
-
Jede unter Punkt 1 angelegt Applikation muss durch Ihren RELion-Super-User jeweils in beiden Instanzen (Produktiv und Sandbox) auf der Seite Microsoft Entra-Anwendungen separat angelegt, aktiviert und berechtigt werden.
- Folgende Berechtigungssätze sind für die Ersteinrichtung sinnvoll.
- RE URA
- SUPER (DATA)
- D365 AUTOMATION
- Eine Einschränkung bzw. feinere Einrichtung kann und soll im Laufe der Anbindung des jeweiligen zugreifenden Programms vorgenommen werden.
- Bitte teilen Sie uns die grundlegende ODataV4-URL der jeweiligen Instanz mit. Sie finden diese auf der Seite Webdienst und sieht zum Beispiel so aus: https://kunde.dynamicstocloud.com:1103/ST-123456
- Folgende Berechtigungssätze sind für die Ersteinrichtung sinnvoll.
-
Von Seiten Aareon RELion wird die Installation der Universal REST API-Extension vorgenommen und die notwendigen Einstellungen an den beiden Instanzen (Produktiv und Sandbox) vorgenommen.
Konfiguration
Hier werden alle Einrichtungen mit deren Verhalten beschrieben. Die Obsolete Einrichtungen werden zwar in der Einrichtungsoberfläche noch angezeigt, haben aber keine Auswirkung mehr und werden hier auch nicht mehr näher beschrieben.
Es können pro Mandant verschiedene Einrichtungen vorgenommen werden. Wenn der von uns empfohlene Standard genutzt werden möchte, dann brauchen die Einstellungen nicht angepasst zu werden.
Empfehlung: In allen Mandanten die gleiche Einrichtung zu verwenden.
Code
Code – Feld, über den Wert dieses Feldes kann bei einem Request eine bestimmte Konfiguration gewählt werden. Die Konfiguration mit einem leeren Code Feld ist die Konfiguration, die als Standard zur Anwendung kommt, wenn keine Konfiguration bei einem Request enthalten ist.
Debug
Aktivert das Dugging. Folgende Einstellungen sind hier möglich:
- Off: kein Logging von eingehenden Aufrufen und Antworten
- Full: Logging von Aufrufe und Antworten
- Request: nur Logging der Aufrufe
- Response: nur Logging der Antworten
ACHTUNG: Nicht unnötg aktivieren, da hierdurch zum einem Daten und damit Speicher belegt wird und zum anderen dadurch die Performance eines Request deutlich vermindert wird.
Response Format
Es kann zwischen den Standard Formaten 0,1,2 und 9 gewählt werden. Es kann nur ein Responseformat für alle Datentypen gewählt werden. Die unterschiede zwischen den Format Typen kann der Microsoft Doku entnommen werden: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-format-property
Wir empfehlen das Format 9 zu verwenden, da es Regions und Sprachunabhängig immer Eindeutig ist. Auch wenn Microsoft es als “XML” Format bezeichnet, wird selbstverständlich ein JSON zurück geliefert. Mit XML-Format ist gemeint, dass es so formatiert wird, dass es auch in einer XML-Datei genau so formatiert ist.
Beispiel: es gibt bei Zahlen keinen Tausender Trennzeichen und das “Komma” ist immer in allen Sprachen ein “Punkt”.
Enum Possible Values
Manchmal benötigt ein System, die Information, welche Options/Enum-Werte möglich sind bei einem Feld. Wird dies Einstellung auf true gesetzt, so wird das Response Object immer so erweitert, das zu einem Enum/Option auch die dazu gehörigen Möglichkeiten geliefert werden.
Empfehlung: Diese Einstellung nur in der Entwicklung auf true lassen. Eventuel ein Setup “DEV” anlegen, wo dieser Wert auch true ist. Ansonsten werden hier sonst unnötige Datenmengen im Trafik erzeugt werden.
Number of Entities To Read
Gibt die maximale Anzahl an Datensätzen an, die in einem request übertragen werden sollen. Dieser Wert kann im Request über den “top” Parameter übersteuert werden.
Field Name Replace From/To Char
Mit diesen beiden Werten kann ein allgemeines Suchen und Ersetzen im Feldnamen umgesetzt werden. Wenn also Als Beispiel die Leerzeichen durch ein Unterstrich im Feldnamen ersetzt ode rganz entfernt werden sollen.
2.3 - GUI-Tool
Übersicht
Dieses PowerShell-Skript stellt eine grafische Benutzeroberfläche (GUI) zur Verfügung, um das Erstellen von JSON-Anfragen für die Universal REST API
zu erleichtern. Es ist darauf ausgelegt, Systemadministratoren und Entwicklern durch interaktive GUI-Elemente den Prozess des korrekten Aufbaus einer Anfrage zu führen.
GUI-Komponenten
Server-Informationen
- RELion Server: Geben Sie hier die Adresse des RELion-Servers ein. Dieser kann in
apiConfig.json
im Parameterserver
gespeichert werden. - RELion API Service: Geben Sie den spezifischen Dienstnamen für den RELion-Server ein. Dieser kann in
apiConfig.json
im Parameterservice
gespeichert werden. - Service Protokoll: Wählen Sie
https
, um eine sichere Datenübertragung zu gewährleisten. Dieser kann inapiConfig.json
im Parameterprotocol
gespeichert werden. - Zertifikat Prüfung: Aktivieren Sie dieses Kästchen, um die Zertifikatüberprüfung für zusätzliche Sicherheit zu aktivieren. Dieser kann in
apiConfig.json
im ParametercheckCert
gespeichert werden. - Mandant GUID: Geben Sie hier die GUID des Mandanten zur Identifizierung ein oder verwenden Sie den ⭮-Button um die vorhandenen Mandanten per WebService einzulesen und danach einen auszuwählen. Die GUID kann in
apiConfig.json
im ParametercompanyGuid
gespeichert werden.
Zugangsdaten
- Credentials: Wählen Sie über dieses Dropdown-Menü die Authentifizierungsmethode aus, die am RELion-Dienst eingerichtet ist.
- Windows: Steht für RELion ONE nicht zur Verfügung.
- User & Password
- Benutzer: Geben Sie den Benutzernamen ein. Dieser kann in
apiConfig.json
im Parameteruser
gespeichert werden. - Passwort: Geben Sie das Passwort ein. Dieses kann nicht in
apiConfig.json
gespeichert werden.
- Benutzer: Geben Sie den Benutzernamen ein. Dieser kann in
- OAuth 2.0
- Tenant-Id: Die eindeutige Kennung Ihres Microsoft-Tenants muss hier eingegeben werden. Diese kann in
apiConfig.json
im Parametertenant
gespeichert werden. - Client-Id: Geben Sie die Anwendungsidentifikation ein. Diese kann in
apiConfig.json
im Parameterapp
gespeichert werden. - Client-Secret: Geben Sie das Anwendungsgeheimnis ein. Dieses kann nicht in
apiConfig.json
gespeichert werden.
- Tenant-Id: Die eindeutige Kennung Ihres Microsoft-Tenants muss hier eingegeben werden. Diese kann in
URA-Kopfdaten
- RELion Tabelle: Wählen Sie die gewünschte Tabelle anhand ihres internen (englischen) Namens aus. Sie können in dem Feld auch schreiben und per Pfeil-runter-Taste die Tabelle auswählen.
- Operation: Wählen Sie die Art der Operation, wie zum Beispiel
READ
, aus diesem Dropdown-Menü. Weitere Informationen zu den einzelnen Optionen entnehmen Sie bitte der Dokumentation zur Universal REST API.
URA-Suboperationen
- Feld hinzufügen: Ein neues Feld zur Anfrage hinzufügen.
- Typ ergänzen: Zeigt den Datentyp und ggf. die Optionen zu den hinzugefügten Felder an.
- Operation hinzufügen: Eine neue Operation in die Anfrage einfügen.
- Antwortfeld hinzufügen: Ein neues Antwortfeld für die Anfrage hinzufügen.
- Body erstellen: Den JSON-Body für die Anfrage konstruieren.
- Senden: Die Anfrage an den Server senden.
- Alles Zurücksetzen: Alle Felder und Auswahlmöglichkeiten im Bereich der uRA-Suboperationen auf den Standardzustand zurücksetzen.
Bedienprozess
flowchart TD classDef Aareon_blue fill:#051163,stroke:#051163,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Bright_blue fill:#086DFB,stroke:#086DFB,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Sand fill:#F7F3F0,stroke:#F7F3F0,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Stone fill:#EBE3DC,stroke:#EBE3DC,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Coral fill:#FF7F62,stroke:#FF7F62,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Peach fill:#FFD8CA,stroke:#FFD8CA,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Green fill:#50B214,stroke:#50B214,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Light_green fill:#B9E99C,stroke:#B9E99C,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Baby_blue fill:#A4CBFF,stroke:#A4CBFF,color:#081326,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Burgundy fill:#550000,stroke:#550000,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif classDef Dark_green fill:#2F630E,stroke:#2F630E,color:#FFFFFF,font-family:Segoe UI, Arial, Helvetica,sans-serif %% linkStyle default color:#ffffff A["Skript (neu) starten"]:::Aareon_blue B["Server-Informationen erfassen"]:::Aareon_blue C["Zugangsdaten erfassen"]:::Aareon_blue D1["Mandanten einlesen und auswählen"]:::Aareon_blue D2["Mandanten-Guid erfassen"]:::Aareon_blue E["Tabelle und Operation auswählen"]:::Bright_blue F1["Benötigte Anzahl Felder hinzufügen"]:::Stone F2{"Alle Felder definiert?"}:::Stone F3["Feld auswählen"]:::Stone F4["Falls Filterfeld, entsprechend markieren"]:::Stone F5["Wert angeben"]:::Stone G1["Operation hinzufügen"]:::Stone G2["Operation 'DONE' auswählen"]:::Stone H["Reiter 'Antwortfelder' auswählen"]:::Sand I1["Benötigte Anzahl Antwortfelder hinzufügen"]:::Sand I2{"Alle Antwortfelder definiert?"}:::Sand I3["Antwortfeld auswählen"]:::Sand J["Reiter 'Body' auswählen"]:::Coral K["Body erstellen"]:::Coral L["Reiter 'Result' auswählen"]:::Peach M["Senden"]:::Peach A --> B B --> C C --> D1 C --> D2 D1 --> E D2 --> E E --> F1 F1 --> F2 F2 -->|"Nein"| F3 F3 --> F4 F4 --> F5 F5 --> F2 F2 -->|"Ja"| G1 G1 --> G2 G2 --> H H --> I1 I1 --> I2 I2 -->|"Nein"| I3 I3 --> I2 I2 -->|"Ja"| J J --> K K --> L L --> M
Versionsgeschichte und Änderungsprotokoll
v1.0.1.3 (Vorab-Version)
- Erhöhung der Parse-Tiefe in der JSON-Verarbeitung, um die möglichen Optionswerte zu unterstützen
- Umbau auf Auswahl der Authentifizierungsmethode per ComboBox
- Hinzufügen der Unterstützung von OAuth 2.0
- Added RENAME-operation
v1.0.1.0
- Umstellung auf vollständig dynamische Parameter bei Invoke-RestMethod. Dadurch auch abwärtskompatible Verwendung von -AllowUnencryptedAuthentication.
- Leeren der Ergebnisbox bei erfolgreichem Aufrufen des Mandanten- bzw. Feld-WebService
- Speicherung der per WebService erhaltenen Feld-Informationen. Dazu werden die im Tool ausgelieferten Informationen mit den neu erhaltenen überschrieben und in einer neuen Datei abgespeichert.
- Mandantennamen werden anstelle leerer Mandanten-Anzeigenamen verwendet.
v1.0.0.0
- Erstveröffentlichung mit vollständiger Funktionalität für das Erstellen von JSON-Anfragebodies über die GUI.
Hinweis
Dieses Dokument wird aktualisiert, sobald neue Funktionen hinzugefügt oder Änderungen am Skript vorgenommen werden.
2.4 - Beispiele
Einfache Beispiele
Lesen
Kreditor lesen
REQUEST
{
"tableNo": "23",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "*"
},
{
"subOperation": "DONE",
"responseFields": "1|2"
}
]
}
RESPONSE (Auszug)
{
"Data": [
{
"No.": "700001",
"Name": "Hausmeisterei"
},
{
"No.": "700002",
"Name": "Tischlerei Markus Wratschko e.U."
},
{
"No.": "700003",
"Name": "Gemeinde St. Georgen am Kreischberg"
},
...
]
}
Schreiben
Einkaufsrechnung schreiben
REQUEST
{
"tableNo": "38",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "2",
"validate": true,
"value": "700001"
},
{
"subOperation": "DONE",
"responseFields": "2|3"
}
]
}
RESPONSE
{
"Data": [
{
"Buy-from Vendor No.": "700001",
"No.": "10R20-00013"
}
]
}
Aktualisieren
In diesem Beispiel wird das Update der in obigem Beispiel übermittelten Einkaufsrechnung dargestellt. Das kann zum Beispiel interessant sein, wenn die Rechnung erneut an RELion übermitteln werden soll.
Dazu werden zwei Arten von Felder übergeben: Filter-Felder (filter = true) und Schreib-Felder (validate = true/false).
Wichtig ist dabei, dass genügend Filter-Felder angegeben werden, um den zu aktualisierenden Datensatz eindeutig zu identifizieren. Hierzu empfiehlt sich die Angabe aller Primärschlüsselfelder.
REQUEST
{
"tableNo": "38",
"operation": "UPDATE",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "2"
},
{
"fieldNo": "3",
"filter": true,
"value": "10R20-00013"
},
{
"fieldNo": "99",
"validate": true,
"value": "2024-02-28"
},
{
"fieldNo": "24",
"validate": true,
"value": "2024-03-10"
},
{
"subOperation": "DONE",
"responseFields": "3|24|99"
}
]
}
RESPONSE
{
"Data": [
{
"No.": "10R20-00013",
"Due Date": "2024-03-10",
"Document Date": "2024-02-28"
}
]
}
Umbenennen
Verteilungscode ändern
REQUEST
{
"tableNo": "5052255",
"operation": "RENAME",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "2"
},
{
"fieldNo": "2",
"filter": true,
"value": "140701"
},
{
"fieldNo": "3",
"filter": true,
"value": "0-QM-NFL"
},
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "2",
"validate": true,
"value": "140701"
},
{
"fieldNo": "3",
"validate": true,
"value": "0-QM-NF"
},
{
"subOperation": "DONE",
"responseFields": ""
}
]
}
RESPONSE
{
"Data": [
{
"Owner / Tenant": "2",
"Object No.": "140701",
"Allocation code": "0-QM-NF",
"Description": "m² Nutzfläche",
"Description on accounting": "0",
"Total factor": "532.92",
"Absolute factor": "false",
"Extrapolation": "0",
"Sum lower units/objects": "0",
"Automatically determined": "false",
"Fixed date": "2021-01-19",
"$systemId": "{712E0A5F-D86B-EB11-B843-005056958D1C}",
"SystemCreatedAt": "",
"SystemCreatedBy": "{00000000-0000-0000-0000-000000000000}",
"SystemModifiedAt": "2024-09-27T09:17:21.748Z",
"SystemModifiedBy": "{7682B4AA-F082-4DCA-802D-E36C1455D4C5}"
}
]
}
Löschen
Einkaufsrechnung löschen
REQUEST
{
"tableNo": "38",
"operation": "DELETE",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "2"
},
{
"fieldNo": "3",
"filter": true,
"value": "10R20-00013"
},
{
"subOperation": "DONE",
"responseFields": "3"
}
]
}
RESPONSE
{
"Data": [
{
"No.": "10R20-00013",
"Due Date": "2024-03-10",
"Document Date": "2024-02-28"
}
]
}
Letzte Zeile lesen
Kreditor lesen
REQUEST
{
"tableNo": "23",
"operation": "READLAST",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "*"
},
{
"subOperation": "DONE",
"responseFields": "1|2"
}
]
}
RESPONSE
{
"Data": [
{
"No.": "WEG14581",
"Name": "WEG St. Georgen ob Murau Bau 12"
}
]
}
Fortgeschrittene Beispiele
Schreiben von Bemerkungszeilen
In diesem Beispiel werden zusätzliche Einkaufsrechnungszeilen angelegt, die nur Bemerkungszwecken dienen.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Belegart | Rechnung = 2 |
3 | Belegnr. | |
4 | Zeilennr. | |
11 | Beschreibung |
REQUEST
{
"tableNo": "39",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "3",
"validate": true,
"value": "10R20-00013"
},
{
"fieldNo": "4",
"validate": true,
"value": "30000"
},
{
"fieldNo": "11",
"validate": true,
"value": "Bemerkungstext"
},
{
"subOperation": "DONE",
"responseFields": "1|3|4|11"
}
]
}
RESPONSE
{
"Data": [
{
"Document Type": "2",
"Document No.": "10R20-00013",
"Line No.": "30000",
"Description": "Bemerkungstext"
}
]
}
Mehrere Sub-Operationen
Einkaufsrechnungskopf
In diesem Beispiel wird ein Einkaufsrechnungskopf (Purchase Header, 38) angelegt und direkt anschließend mit Beleg- und Fälligkeitsdatum aktualisiert. Durch die besondere Natur der BC-Standard-Programmierung ist dieser Zugang beim Einkaufsrechnungskopf notwendig.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Belegart | Rechnung = 2 |
2 | Kreditorennr. | |
3 | Belegnr. | |
24 | Fälligkeitsdatum | |
99 | Belegdatum |
REQUEST
{
"tableNo": "38",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "2",
"validate": true,
"value": "700001"
},
{
"subOperation": "INSERT",
"responseFields": ""
},
{
"fieldNo": "99",
"validate": true,
"value": "2024-02-28"
},
{
"fieldNo": "24",
"validate": true,
"value": "2024-03-10"
},
{
"subOperation": "UPDATE_RESPONSE",
"responseFields": "3|24|99"
}
]
}
RESPONSE
{
"Data": [
{
"No.": "RG24-0015632",
"Due Date": "2024-03-10",
"Document Date": "2024-02-28"
}
]
}
Einkaufsrechnungszeilen
In diesem Beispiel werden mehrere Einkaufsrechnungszeilen (Purchase Line, 39) angelegt. Durch die gemeinsame Übertragung werden entweder alle Datensätze angenommen oder bei einem Fehler gar keiner. Zu beachten ist, dass trotz INSERT_RESPONSE
bei der ersten Suboperation nur die Antwort der letzten Suboperation zurückgegeben wird. Somit hat es keine Auswirkung, wenn statt INSERT_RESPONSE
“nur” INSERT
verwendet wird.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Belegart | Rechnung = 2 |
3 | Belegnr. | |
4 | Zeilennr. | |
5052250 | Eigentümer / Mieter | Mieter = 2 |
5052251 | Objektnr. | |
5052254 | Objektkonto Nr. | |
15 | Menge | |
22 | EK-Preis |
REQUEST
{
"tableNo": "39",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "3",
"validate": true,
"value": "RG24-0015632"
},
{
"fieldNo": "4",
"validate": true,
"value": "10000"
},
{
"fieldNo": "5052250",
"validate": true,
"value": "2"
},
{
"fieldNo": "5052251",
"validate": true,
"value": "140701"
},
{
"fieldNo": "5052254",
"validate": true,
"value": "4410207"
},
{
"fieldNo": "15",
"validate": true,
"value": "1"
},
{
"fieldNo": "22",
"validate": true,
"value": "100"
},
{
"subOperation": "INSERT_RESPONSE",
"responseFields": "1|3|4|5052250|5052251|5052254|15|22"
},
{
"fieldNo": "1",
"validate": true,
"value": "2"
},
{
"fieldNo": "3",
"validate": true,
"value": "RG24-0015632"
},
{
"fieldNo": "4",
"validate": true,
"value": "20000"
},
{
"fieldNo": "5052250",
"validate": true,
"value": "2"
},
{
"fieldNo": "5052251",
"validate": true,
"value": "140701"
},
{
"fieldNo": "5052254",
"validate": true,
"value": "4410215"
},
{
"fieldNo": "15",
"validate": true,
"value": "1"
},
{
"fieldNo": "22",
"validate": true,
"value": "400"
},
{
"subOperation": "DONE",
"responseFields": "1|3|4|5052250|5052251|5052254|15|22"
}
]
}
RESPONSE
{
"Data": [
{
"Document Type": "2",
"Document No.": "RG24-0015632",
"Line No.": "20000",
"Quantity": "1",
"Direct Unit Cost": "400",
"RelC Owner/Tenant": "2",
"RelC Object No.": "140701",
"RelC Object Account No.": "4410215"
}
]
}
Beschränkte Anzahl an Rückgabezeilen
Aus technischen Gründen wird die Anzahl an Datensätzen, die von der Universal Rest API zurückgegeben werden, limitiert. In Fällen, wo die benötigte Anzahl größer ist als das Limit sind somit folgende Eingriffe nötig und möglich.
Pagination
In allen Tabellen lässt sich über die Parameter top
und skip
ein seitenweises Lesen (Pagination) erreichen.
top
gibt dabei die Anzahl an (falls vorhanden) zurückzugebenden Datensätzen darskip
gibt an, wie viele Datensätze davor übersprungen werden sollen
D.h. in untenstehendem Beispiel werden zuerst 6 Datensätze übersprungen und dann die nächsten 3 zurückgegeben.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Lfd. Nr. | |
3 | Sachkontonr. | |
4 | Buchungsdt. |
REQUEST
{
"tableNo": "17",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"top": "3",
"skip": "6",
"entitySet": [
{
"subOperation": "DONE",
"responseFields": "1|3|4"
}
]
}
WebService-Response (Auszug)
{
...
"skip": 6,
"top": 3,
"entitySet": [
{
...
"totalCount": 24447,
"skippedRows": 6,
"moreRows": true,
"countOfReturnRows": 3,
"ResponseJson2": ...
}
]
}
WebService-Response sind folgende Parameter in diesem Zusammenhang interessant:
totalCount
gibt die Anzahl der insgesamt dem Filter entsprechenden Datensätze zurück. Dieser Wert ist von den Request-Parameternskip
undtop
unabhängig.skippedRows
gibt die tatsächlich übersprungene Anzahl an Datensätzen zurück und entspricht somit dem kleineren folgender Werte:skip
,totalCount
countOfReturnRows
gibt die tatsächliche Anzahl an zurückgegebenen Datensätzen an und bewegt sich somit zwischen0
undtop
.moreRows
ermöglicht eine einfache Schleifenbedingung für die Abfragen und gibt die Wertetrue
oderfalse
zurück.
RESPONSE (Auszug)
{
"Data": [
{
"Entry No.": "7",
"G/L Account No.": "80600501",
"Posting Date": "2019-01-01"
},
{
"Entry No.": "8",
"G/L Account No.": "190016",
"Posting Date": "2019-01-01"
},
{
"Entry No.": "9",
"G/L Account No.": "1420",
"Posting Date": "2019-01-01"
}
]
}
Wiederholtes Lesen mit verändertem Filter auf dem Primärschlüssel-Feld
Welches Feld bzw. welche Felder je Tabelle den Primärschlüssel bilden, können Sie in der Seitenüberprüfung (Strg+Alt+F1) sehen.
In der Antwort der Universal REST API werden auf der selben Ebene wie das ResponseJson2
noch die Felder numberOfRows
und moreRows
zurückgegeben.
numberOfRows
gibt die Anzahl an Datensätzen an, die insgesamt gefunden wurden. In untenstehendem Beispiel wird sie also bei jedem Aufruf kleiner.moreRows
gibt einen boolschen Wert zurück, der anzeigt, ob noch mehr Datensätze vorhanden sind, die aufgrund des Limits nicht übertragen wurden.
Ein Beispiel für das Lesen der Sachkonten, würde wie folgt aussehen:
1. REQUEST
{
"tableNo": "15",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": ">0"
},
{
"subOperation": "DONE",
"responseFields": "1|2|4"
}
]
}
1. RESPONSE (Auszug)
{
"Data": [
{
"No.": "000-",
"Name": "Anlagevermögen",
"Account Type": "3"
},
...
{
"No.": "08100",
"Name": "Ausleihungen an verbundene Unternehmen",
"Account Type": "0"
}
]
}
Nun muss auf Basis des zuletzt zurückgegebenen Primärschlüssels der nächste Request aufgebaut werden.
2. REQUEST
{
"tableNo": "15",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": ">08100"
},
{
"subOperation": "DONE",
"responseFields": "1|2|4"
}
]
}
2. RESPONSE (Auszug)
{
"Data": [
{
"No.": "08130",
"Name": "Ausleihungen an verbundene UN, PersG",
"Account Type": "0"
},
...
{
"No.": "12960",
"Name": "WB Forderg.gg.UN m.Beteiligg.verh. b.1J",
"Account Type": "0"
}
]
}
Das Ganze muss wiederholt werden, bis das Feld moreRows
den Wert false
zurückgibt.
3. REQUEST
{
"tableNo": "15",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": ">12960"
},
{
"subOperation": "DONE",
"responseFields": "1|2|4"
}
]
}
usw.
Maximalanzahl der zu übertragenden Datensätze in der uRA-Einrichtung erhöhen
Dies stellt eine grundsätzliche Möglichkeit dar. Allerdings ist zu beachten, dass bei einer zu großen Anzahl an Datensätzen, die Anfrage an die Universal Rest API in ein Timeout laufen wird. Daher stellt dies die schlechteste Möglichkeit dar und ist hier nur mehr der Vollständigkeit halber erwähnt.
Filterung nach Änderungsdatum
Eine Abfrage aller RELion-Objekte mit Änderungen seit 01.03.2023 würde wie folgt aussehen.
Zu beachten ist, dass die Datumsformatierung standardmäßig auf XML-Format eingestellt ist. Diese ist im Sinne einer Systemkompatibilität klar zu bevorzugen, kann aber in der Universal Rest API Settings je Mandant und Einrichtungscode geändert werden.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Eigentümer / Mieter | Eigentümer = 1 |
Mieter = 2 | ||
2 | Objektnr. | |
2000000003 | Geändert am |
REQUEST
{
"tableNo": "5052250",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "2000000003",
"filter": true,
"value": ">2023-03-01T00:00:00Z"
},
{
"subOperation": "READ",
"responseFields": "1|2|2000000003"
}
]
}
RESPONSE
{
"Data": [
{
"Owner / Tenant": "1",
"No.": "416502",
"SystemModifiedAt": "2023-10-09T14:20:40.247Z"
},
{
"Owner / Tenant": "2",
"No.": "416501",
"SystemModifiedAt": "2023-10-09T14:20:41.427Z"
}
]
}
RecordLinks
Links und Notizen werden in der Tabelle 2000000068 abgelegt.
Für die folgenden Beispiele werden verwendet:
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Link ID | |
2 | Record ID | |
3 | URL | |
7 | Beschreibung | |
10 | Erstellt | |
11 | Benutzer ID | |
12 | Mandant | |
8 | Typ | |
9 | Notiz |
Schreiben von Links
Das folgende Beispiel zeigt das Hinzufügen eines Links zu einem Einkaufsrechnungskopf. Zu beachten ist dabei vor allem die korrekte Angabe im Feld Record ID
. Diese besteht aus dem Tabellennamen und allen Primärschlüsselfeldern des Datensatzes, dem der Link hinzugefügt werden soll.
REQUEST
{
"tableNo": "2000000068",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "2",
"validate": true,
"value": "Purchase Header: Invoice,ER1802820"
},
{
"fieldNo": "3",
"validate": true,
"value": "http://www.aareon.com"
},
{
"fieldNo": "7",
"validate": true,
"value": "URL"
},
{
"fieldNo": "10",
"validate": true,
"value": "2024-02-29 11:00:00"
},
{
"fieldNo": "11",
"validate": true,
"value": "AAREON\\HIEDEN"
},
{
"fieldNo": "12",
"validate": true,
"value": "10_Mietverwaltung"
},
{
"subOperation": "DONE"
}
]
}
RESPONSE
{
"Data": [
{
"Link ID": "21782",
"Record ID": "Purchase Header: 2,ER1802820",
"URL1": "http://www.aareon.com",
"Description": "URL",
"Type": "0",
"Note": " ",
"Created": "29.02.24 11:00",
"User ID": "AAREON\\HIEDEN",
"Company": "10_Mietverwaltung",
"Notify": "0",
"To User ID": "",
"$systemId": "01D1865D-C7D7-EE11-AD31-00505699FC69",
"SystemCreatedAt": "29.02.24 11:00",
"SystemCreatedBy": "7FEAA26B-6F07-4EF6-9BDA-6537D587E5C3",
"SystemModifiedAt": "29.02.24 11:00",
"SystemModifiedBy": "7FEAA26B-6F07-4EF6-9BDA-6537D587E5C3"
}
]
}
Schreiben von Notizen
In diesem Beispiel wird eine Notiz der selben Einkaufsrechnung hinzugefügt.
REQUEST
{
"tableNo": "2000000068",
"operation": "INSERT",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "2",
"validate": true,
"value": "Purchase Header: Invoice,ER1802820"
},
{
"fieldNo": "8",
"validate": true,
"value": "1"
},
{
"fieldNo": "9",
"validate": true,
"value": "MURpZXNlIE5vdGl6IHd1cmRlIHBlciB1bml2ZXJzYWwgUmVzdCBBUEkgZXJ6ZXVndC4="
},
{
"fieldNo": "10",
"validate": true,
"value": "2024-02-29 11:00:00"
},
{
"fieldNo": "11",
"validate": true,
"value": "AAREON\\HIEDEN"
},
{
"fieldNo": "12",
"validate": true,
"value": "10_Mietverwaltung"
},
{
"subOperation": "DONE",
"responseFields": "1|2|3|7|8|9"
}
]
}
RESPONSE
{
"Data": [
{
"Link ID": "9288",
"Record ID": "Purchase Header: 2,ER1802820",
"URL1": "",
"Description": "",
"Type": "1",
"Note": "MURpZXNlIE5vdGl6IHd1cmRlIHBlciB1bml2ZXJzYWwgUmVzdCBBUEkgZXJ6ZXVndC4="
}
]
}
Änderung von RecordLinks
In diesem Beispiel wird das Ziel des RecordLinks geändert. Hierzu muss nicht mehr die Record ID
angegeben werden, sondern es reicht, die einfacher zu verwendende Link ID zu übermitteln, die wir beim Hinzufügen erhalten haben.
REQUEST
{
"tableNo": "2000000068",
"operation": "UPDATE",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "21782"
},
{
"fieldNo": "3",
"validate": true,
"value": "http://www.relion.de"
},
{
"subOperation": "DONE",
"responseFields": "1|2|3"
}
]
}
RESPONSE
{
"Data": [
{
"Link ID": "21782",
"Record ID": "Purchase Header: 2,ER1802820",
"URL1": "http://www.relion.de"
}
]
}
Lesen von RecordLinks
In diesem Beispiel werden die RecordLinks (Links & Notizen) einer Einkaufsrechnung gelesen.
REQUEST
{
"tableNo": "2000000068",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "2",
"filter": true,
"value": "Purchase Header: Invoice,ER1802820"
},
{
"subOperation": "DONE",
"responseFields": "1|2|3|7|8|9"
}
]
}
RESPONSE
{
"Data": [
{
"Link ID": "21782",
"Record ID": "Purchase Header: 2,ER1802820",
"URL1": "http://www.relion.de",
"Description": "URL",
"Type": "0",
"Note": ""
}
]
}
Dimensionen
Lesen von Dimensionswerten
In diesem Beispiel werden die Dimensionswerte auf den Sachposten ausgelesen.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Lfd. Nr. | |
3 | Sachkontonr. | |
17 | Betrag | |
23 | Globaler Dimensionscode 1 | |
24 | Globaler Dimensionscode 2 | |
481 | Shortcutdimensionscode 3 | |
482 | Shortcutdimensionscode 4 | |
483 | Shortcutdimensionscode 5 | |
484 | Shortcutdimensionscode 6 | |
485 | Shortcutdimensionscode 7 | |
486 | Shortcutdimensionscode 8 |
REQUEST
{
"tableNo": "17",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "24",
"filter": true,
"value": "WEG SCHW."
},
{
"subOperation": "DONE",
"responseFields": "1|3|17|23|24|481|482|483|484|485|486"
}
]
}
RESPONSE (Auszug)
{
"Data": [
{
"Entry No.": "2559",
"G/L Account No.": "608076",
"Amount": "-50",
"Global Dimension 1 Code": "OBJ001",
"Global Dimension 2 Code": "WEG SCHW.",
"Shortcut Dimension 3 Code": "",
"Shortcut Dimension 4 Code": "",
"Shortcut Dimension 5 Code": "",
"Shortcut Dimension 6 Code": "",
"Shortcut Dimension 7 Code": "",
"Shortcut Dimension 8 Code": ""
},
{
"Entry No.": "2560",
"G/L Account No.": "200010",
"Amount": "50",
"Global Dimension 1 Code": "OBJ001",
"Global Dimension 2 Code": "WEG SCHW.",
"Shortcut Dimension 3 Code": "",
"Shortcut Dimension 4 Code": "",
"Shortcut Dimension 5 Code": "",
"Shortcut Dimension 6 Code": "",
"Shortcut Dimension 7 Code": "",
"Shortcut Dimension 8 Code": ""
},
...
]
}
Auslesen möglicher Dimensionswerte
In diesem Beispiel werden die möglichen Dimensionswerte für die Dimension ABTEILUNG ausgelesen.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Dimensionscode | |
2 | Code | |
3 | Name | |
4 | Dimensionswertart | Standard = 0 |
6 | Gesperrt | Nein = 0 |
REQUEST
{
"tableNo": "349",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "ABTEILUNG"
},
{
"fieldNo": "4",
"filter": true,
"value": "0"
},
{
"fieldNo": "6",
"filter": true,
"value": "0"
},
{
"subOperation": "DONE",
"responseFields": "1|2|3"
}
]
}
RESPONSE (Auszug)
{
"Data": [
{
"Dimension Code": "ABTEILUNG",
"Code": "100",
"Name": "Bau allgemein"
},
{
"Dimension Code": "ABTEILUNG",
"Code": "110",
"Name": "Planung"
},
{
"Dimension Code": "ABTEILUNG",
"Code": "120",
"Name": "Bauleitung"
},
...
]
}
Dimensionswert schreiben
In diesem Beispiel wird der Dimensionswert für die Dimension ABTEILUNG in einer Einkaufsrechnungszeile aktualisiert.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Belegart | Rechnung = 2 |
3 | Belegnr. | |
4 | Zeilennr. | |
480 | Dimensionssatz-ID |
REQUEST
{
"tableNo": "39",
"operation": "UPDATE",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "2"
},
{
"fieldNo": "3",
"filter": true,
"value": "R22-05048"
},
{
"fieldNo": "4",
"filter": true,
"value": "10000"
},
{
"fieldNo": "480",
"dimensionSetId": true,
"dimensionSetIdMutation": "1"
},
{
"dimension": true,
"dimensionCode": "ABTEILUNG",
"value": "100"
},
{
"subOperation": "DONE",
"responseFields": "3|480"
}
]
}
RESPONSE
{
"Data": [
{
"Document No.": "R22-05048",
"Dimension Set ID": "22481"
}
]
}
Tabellen- und Feldinformationen
Über die Universal Rest API ist es auch möglich, die Tabellen und Feldinformationen aus den System-Tabellen AllObjWithCaption
und Field
auszulesen.
Tabelleninformationen
Die System-Tabelle AllObjWithCaption
beinhaltet Informationen zu allen in der Business Central-Instanz vorhandenen Programmobjekte (Tabellen, Seiten, Berichte, …). Für die Arbeit mit der Universal Rest API sind für allem die Informationen zu den vorhandenen Tabellen relevant.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | Objekttyp | Tabelle = 1 |
3 | Objekt-ID | |
4 | Objektname |
REQUEST
{
"tableNo": "2000000058",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "1"
},
{
"subOperation": "DONE",
"responseFields": "3|4"
}
]
}
RESPONSE (Auszug)
{
"Data": [
{
"Object ID": "3",
"Object Name": "Payment Terms"
},
{
"Object ID": "4",
"Object Name": "Currency"
},
{
"Object ID": "5",
"Object Name": "Finance Charge Terms"
},
...
]
}
Feldinformationen
Die System-Tabelle Field
beinhaltet Informationen zu allen in der Business Central-Instanz vorhandenen Tabellenfeldern.
Feldnummer | Feldbezeichnung | Optionswert |
---|---|---|
1 | TableNo | Tabelle = 1 |
2 | Nr. | |
3 | TableName | |
4 | FieldName | |
5 | Typ | |
6 | Länge | |
7 | Klasse | |
8 | Aktiviert | Ja = 1 |
9 | Typname | |
20 | Feldbezeichnung | |
23 | SQLDataType | |
24 | OptionString | |
28 | IsPartOfPrimaryKey |
REQUEST
{
"tableNo": "2000000041",
"operation": "READ",
"runTrigger": true,
"setupCode": "",
"entitySet": [
{
"fieldNo": "1",
"filter": true,
"value": "5052250"
},
{
"fieldNo": "8",
"filter": true,
"value": "1"
},
{
"subOperation": "DONE",
"responseFields": "1|2|3|4|5|6|7|9|20|23|24|28"
}
]
}
RESPONSE (Auszug)
{
"Data": [
{
"TableNo": "5052250",
"No.": "1",
"TableName": "RelC Object",
"FieldName": "Owner / Tenant",
"Type": "35583",
"Len": "4",
"Class": "0",
"Type Name": "Option",
"Field Caption": "Owner / Tenant",
"SQLDataType": "0",
"OptionString": "None,Owner,Tenant",
"IsPartOfPrimaryKey": "true"
},
{
"TableNo": "5052250",
"No.": "2",
"TableName": "RelC Object",
"FieldName": "No.",
"Type": "31489",
"Len": "20",
"Class": "0",
"Type Name": "Code20",
"Field Caption": "No.",
"SQLDataType": "0",
"OptionString": "",
"IsPartOfPrimaryKey": "true"
},
...
]
}