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:

  1. Webadresse des Servicetiers
  2. Port der BC OData Services
  3. BC Dienstnamen
  4. 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:

Insert Record with URA

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:

  1. Einzelanweisung, ein Datensatz ohne komplexe Trigger und Validierungen über die API einfügen oder verändern.
  2. 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.
  3. 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.
  • 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:

    1. Abschluss einer Operation oder Suboperation
    2. Einfügen von Daten
    3. Ändern von Daten
    4. Löschen von Daten
    5. Lesen von Daten
    6. 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:

    1. 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.
    2. Insert - …… -Insert (BULK) Einfügeoperationen, ein Aufruf schreibt mehrere Datensätze in die Datenbank.
    3. 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:

      1. 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.

      2. 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"
             }
           ]
         }
        
      3. 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.

      4. 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.

      5. 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.

      6. 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.

      7. 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.

      8. 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.

Zuletzt geändert April 9, 2025: Updated Dienst-und-Systemstatus.md (faede55)