Lade...
 

Webservice Spezifikation

Spezifikation des Webservices in ClassiX

Der Webservice in ClassiX wir über den Webservice-Manager gesteuert, welcher über GetManager(WEB_SERVICE) erreichbar ist.

Zur Nutzung des Webservice-Managers muss die DLL mit dem Präfix "cxivsa" in der classix.ini eingebunden sein.

1 Anfragenspezifikation

Anfragen an den Webservice sollten grundsätzlich der HTTP 1.1 Spezifikation folgen. Der Webservice antwortet ausschließlich mit HTTP 1.1 und ignoriert die Versionsangabe bei Anfragen. Anfragen mit anderen Versionsangaben werden als HTTP 1.1-Anfragen interpretiert insofern sie eine gültige HTTP 1.1 Anfrage darstellen.

Jede gültige Anfrage wird vom Webservice in ein CX_HTTP_REQUEST-Objekt gekapselt und mit einer Message geschickt, die sich zusammensetzt aus:

<Pfad>_<Methode>

 

Die einfachste, gültige Anfrage lautet wie folgt:

GET /hello HTTP/1.1

Die Anfrage würde dazu führen, dass ClassiX die Message HELLO_GET aufgerufen wird. Ist diese Message nicht definiert, dann erhält der Client folgende Fehlermeldung im JSON-Format:

HTTP/1.1 501 Not Implemented
Content-Type: application/json
Content-Length: 60

{ "error_message": "No message named \"HELLO_GET\" found." }

 

1.1 HTTP Methoden

Der Webservice unterstützt folgende Anfragemethoden:

  • GET
  • POST
  • PUT
  • DELETE
  • OPTIONS
  • HEAD
  • TRACE
  • CONNECT

Jede dieser Anfragemethoden wird gleich behandelt und besitzt keine besondere Semantik. Die HTTP-Methode wird mit Unterstrich getrennt an den relativen Pfad der HTTP-Anfrage angehängt als Nachricht an ClassiX gesendet. Die verschiedenen HTTP-Methoden können verwendet werden, um die Semantik einer Anfrage für den Nutzer der Webservice-Schnittstelle zu verdeutlichen.

Andere Webservices verbinden häufig folgende Semantiken mit den HTTP-Methoden

Methode Semantik Beispielanfrage Anfragesemantik
GET Objekte nach ID oder Sammlungen von Objekten abfragen GET /person/1234 Person-Objekt mit ID=1234 zurückliefern
POST Objekte anlegen oder ändern POST /person/1234?name=bob Name von Person-Objekt mit ID=1234 auf bob ändern
PUT Objekte anlegen PUT /person/12345 Neues Person-Objekt mit ID=12345 anlegen und mit Werten aus dem Anfrage-Body befüllen
DELETE Objekt löschen DELETE /person/12345 Person-Objekt mit ID=12345 löschen

 

1.2 HTTP Pfad

Da der Pfad der Anfrage und ihre HTTP-Methode vom WebService interpretiert werden, um mithilfe dieser Aktionen in ClassiX auszuführen oder Informationen abzufragen, muss auch dieser den nachfolgenden Konventionen genügen:

Der Pfad ist Case-Insensitive.

Wie auch in der HTTP-Spezifikation, muss der Pfad immer mit einem /(Slash) beginnen. Anschließend gibt es zwei Modi:

1.2.1 Message-Anfragen

Damit in ClassiX eine Message ausgelöst wird, dürfen im Pfad keine weiteren Unterpfade mehr vorkommen.

Ein leerer Pfad GET / HTTP/1.1 ist nicht erlaubt. Ein Pfad darf aber mit einem Slash abschlossen werden und hat dann die gleiche Bedeutung, wie der Pfad ohne den abschließenden Slash.

Bsp: GET /hello/ HTTP/1.1GET /hello HTTP/1.1
1.2.2 Daten-Abfragen

Alternativ können direkt Daten von ClassiX abgefragt werden, ohne InstantView-Code auszuführen. Hierbei besteht der Pfad aus zwei Teilen. Der erste Teil spezifiziert den Typ der Abfrage, der zweite Teil gibt genauere Informationen.

So ist es beispielsweise möglich, mit dem folgenden Befehl direkt die ersten 30 Zeilen einer ObjectListView abzufragen:

GET /widget/.partnedc.SelectWin.123?from=0&count=30 HTTP/1.1

1.3 HTTP Query

An jeden gültigen Pfad kann zusätzlich ein HTTP-Query-String angehängt werden (unabhängig von der verwendeten HTTP-Methode). Über den Query-String können beliebige String-Parameter an den Webservice übergeben werden. Diese lassen sich dann in ClassiX mit GetParameterNames und GetParameter aus dem Anfrageobjekt auslesen.

Der Query-String beginnt immer mit einem ? optional gefolgt von Schlüssel-Wert-Paaren, die durch & getrennt sind. Schlüssel und Wert sind durch = voneinander getrennt.

Bsp: POST /person?name=bob&id=12345 HTTP/1.1

 

Alle Schlüssel und Werte müssen dem URL-Encoding entsprechend kodiert werden, falls reservierte Zeichen oder Nicht-ASCII-Zeichen darin vorkommen. (LEER ! # $ % & ' ( ) * + , / : ; = ? @ )
Damit wird sichergestellt, dass alle möglichen Zeichenketten korrekt übertragen werden.

1.4 HTTP Body Parameter

Der Webservice unterstützt zusätzlich zwei Möglichkeiten, HTTP-Parameter über den Anfrage-Body zu übermitteln. Diese können unabhängig von der verwendeten HTTP-Methode verwendet werden. Im Gegensatz zu gängigen Implementierungen, lässt GET also auch die Übermittlung eines Bodys zu und wertet ihn entsprechend aus.
Parameter, die über den Body übermittelt werden, überschreiben gleichnamige Parameter aus dem Query-String.

1.4.1 x-www-form-urlencoded

Die erste Methode ist das Übermitteln der Parameter als x-www-form-urlencoded und die Beispielanfrage aus 1.3 würde wie folgt aussehen:

POST /person HTTP/1.1
Content-Length: 18a
Content-Type: application/x-www-form-urlencoded

name=bob&id=12345

Wichtig ist hierbei der korrekt gesetzte Content-Type-Header. Der Body der Anfrage enthält den Query-String, wie in 1.3 beschrieben ohne das führende ?. Die übermittelten Schlüssel und Werte müssen ebenfalls dem URL-Encoding entsprechend kodiert werden.

 

1.4.2 form-data

Die zweite Methode ist das Übermitteln der Parameter als multipart/form-data. Diese Methode leitet die einzelnen Werte durch sogenannte Boundaries ein. Das Boundary muss einmalig definiert werden und beim Content-Type-Header mit angegeben werden. Auf das Boundary folgt eine Beschreibung des Parameters und von der übernächsten Zeile bis zum nächsten Boundary der folgt der Wert des Parameters. Die Parameterwerte müssen nicht kodiert werden. Sie werden als UTF-8 kodierte textdaten interpretiert, wenn keine weiteren Angaben gemacht werden. Auf die Content-Disposition-Zeile kann eine Zeile mit Content-Type: optional folgen, die den Content-Type des Parameters setzt. Damit kann gesteuert werden, ob ClassiX den Parameter als UTF-8 Zeichenkette interpretiert, oder als Binardaten. Die Content-Types text/* und application/json werden dabei als textuelle Daten in mit UTF-8-Kodierung interpretiert.
Der Beispielaufruf aus 1.3 könnte wie folgt ausshen:

POST /person HTTP/1.1 Content-Length: 232 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIGuh1UO3zUaUh8J2 ------WebKitFormBoundaryIGuh1UO3zUaUh8J2 Content-Disposition: form-data; name="name" bob ------WebKitFormBoundaryIGuh1UO3zUaUh8J2 Content-Disposition: form-data; name="id" 12345 ------WebKitFormBoundaryIGuh1UO3zUaUh8J2--

 

Der Webservice unterstützt NICHT die Übertragung von komprimierten Parametern (gzip oder ähnliches). Alle Parameter werden als Strings an ClassiX weitergegeben. Strings können in ClassiX keine NULL-Bytes enthalten. Für die Übertragung von binären Dateien empfiehlt es sich die Daten vor der Übertragung mit Base64 zu kodieren und den kodierten Parameter in Classix mit CX_BASE64::DecodeFile in eine Datei zu dekodieren.

 

Im Gegensatz zur HTTP 1.1 Spezifikation, ist das Host-Feld NICHT VERPFLICHTEND. Eine Anfrage ohne das Host-Feld wird vom Webservice als valide HTTP 1.1-Anfrage akzeptiert. Der Wert des Host-Felds wird vom Webservice selbst nicht ausgewerted, wie in Abschnitt 5.2 der HTTP 1.1 Spezifikation beschrieben. Das Host-Feld kann über CX_HTTP_REQUEST::GetHeader() im InstantView-Code ausgewertet werden.

Wird ein Body übermittelt SOLLTE immer das Content-Length-Feld auf die Länge des übermittelten HTTP-Bodies gesetzt werden. Wird das Feld nicht gesetzt, dann garantiert der Webservice nicht, dass der gesamte Body vollständig an ClassiX weitergegeben wird.

Momentan gibt es einen Fehler in der verwendeten Webservice-Bibliothek, die dafür sorgt, dass der Webservice nicht auf Anfragen reagiert, in denen bereits mehr Daten im Body übertragen wurden, als im Content-Length:-Feld angegeben

Zusätzlich zu Content-Length SOLLTE bei einem übermittelten Body immer das Content-Type Feld gesetzt werden, damit der Webservice weiß, wie er die empfangenen Daten interpretieren soll. Konkret bedeutet das, dass der Webservice für die Content-Types text/* und application/json den Body als UTF-8 kodiert interpretiert. Anderenfalls wird der Body wie Binärdaten behandelt und es findet keine Konvertierung statt.
Soll ein anderer Content-Type ebenfalls als UTF-8 kodierte Zeichenkette interpretiert werden, dann lässt sich dies durch das explizite Angeben des charsets erreichen.

Beispiel: Content-Type: application/xml; charset=utf-8

 

Alle weiteren Header-Felder werden nicht interpretiert und werden einfach nur an ClassiX weitergereicht. Die Header können aus dem Anfrageobjekt über die Methoden GetHeaderNames und GetHeader ausgelesen werden.

Diese Umsetzung kann aktuell zu Performance-Problemen führen, wenn der Client den Header Expect: 100-continue bei POST-Anfragen setzt. Der Server reagiert aktuell nicht wie im RFC vorgegeben auf diesen Header, was dazu führt, dass der Client in einem Timeout läuft, ehe der Body übertragen wird. Als Workaround sollte dieser Header aktuell nicht verwendet werden.

 

2 Antwortspezifikation

Die Antworten werden vom Webservice aus CX_HTTP_RESPONSE-Objekten erzeugt.

2.1 Statuscodes

2.2 Headerfelder

Der Webservice setzt nur das Header-Feld Content-Length automatisch. Alle weiteren Header-Felder können über das CX_HTTP_RESPONSE-Objekt beliebig gesetzt werden.

Sollte der ClassiX-Fehlermeldungen werden im JSON-Format an den Client gesendet und dann setzt der Webservice zusätzlich das Header-Feld Content-Type auf application/json.

2.3 Body

Der Antwortbody ist immer UTF-8 kodiert. Fehlermeldungen werden im JSON-Format an den Client gesendet. Das Feld error_message enthält die Fehlermeldung.

Verwandte Themen