Daten exponieren mit OData und Apache Olingo

Seite 3: HTTP und Abfragen

Inhaltsverzeichnis

Wendet man HTTP-PATCH/HTTP-MERGE auf die eindeutige URI einer Entität an, werden alle im Request Body geschickten Property-Felder gelesen und entsprechend bei der Entität aktualisiert. Im Gegensatz zum HTTP-PUT interpretiert das System nicht im Request-Body mitgeschickte Property-Felder jedoch nicht als NULL, sondern ignoriert sie beim Update einfach.

Die Key-Property-Felder sind im Request Body nicht mitzuschicken, da sie bereits in der eindeutigen URI der Entität vorhanden sind. Entsprechend lassen sie sich auch nicht durch ein Update verändern. Werden die Key-Property-Felder im Request-Body mitgeschickt, kann der OData-Service entscheiden, ob er mit einem Fehler reagiert oder sie beispielsweise einfach ignoriert.

Sowohl beim HTTP-PUT als auch beim HTTP-PATCH / HTTP-MERGE ist bei einem erfolgreichem Update das Ergebnis ein HTTP Response mit einem Status von 204: No Content.

Im aktuellen Beispiel wäre das ein PUT auf die URI ../OData.svc/Car('1') mit Content-Type=application/atom+xml und folgendem Content im HTTP BODY, um den Preis (d:Price) zu aktualisieren.

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m=↩
"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xml:base="http://localhost:8080/MyFormula.svc/">
<content type="application/xml">
<m:properties>
<d:Model>F1 W02</d:Model>
<d:Price>47110.0</d:Price>
<d:ModelYear>2011</d:ModelYear>
<d:Updated>2014-01-30T09:13:34.847</d:Updated>
</m:properties>
</content>
</entry>

Wie man sieht, sind bei einem HTTP-PUT auch die übrigen Felder (d:Model, d:ModelYear, i]d:Updated[/i]) mit ihren alten Werten mitzuschicken, um nicht auf NULL gesetzt zu werden.

Um sich das nicht notwendige Mitsenden der Felder, deren Wert sich nicht ändert (d:Model, d:ModelYear, d:Updated), zu ersparen, lässt sich ein HTTP-PATCH- / HTTP-MERGE-Requests verwenden. Die URI bleibt ebenso identisch ../OData.svc/Car('1') wie der Content-Type=application/atom+xml. Jedoch reicht jetzt folgender Content im HTTP BODY, um nur den Preis (d:Price) zu aktualisieren:

<?xml version='1.0' encoding='utf-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m=↩
"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xml:base="http://localhost:8080/MyFormula.svc/">
<content type="application/xml">
<m:properties>
<d:Price>47110.0</d:Price>
</m:properties>
</content>
</entry>

Beide Beispiele resultieren darin, dass der Preis des Autos aktualisiert wurde. Der einzige Unterschied ist, dass im Request Body weniger Daten zu schicken sind.

Für das Löschen einer Entität ist ein HTTP-DELETE-Aufruf auf die eindeutige URI der Entität durchzuführen. Im aktuellen Beispiel wäre das ein DELETE auf die URI ../OData.svc/Cars('1'), um das Auto mit dem Key von 1 zu löschen, was in einem HTTP-Response-Status von 204: No Content resultiert.

Ein direkt danach ausgeführter lesender Zugriff auf die Entität (per HTTP-GET auf die URI ../OData.svc/Cars('1')) würde dann ein in einem HTTP-Response-Status von 404: Not Found resultieren.

In OData gibt es sogenannte System Query Options, die dazu dienen, Abfragen näher zu spezifizieren. Dazu sind folgende HTTP-Query-Parameter mit vorgestelltem $ als Schlüsselworte reserviert: $expand, $filter, $orderby, $format, $skip, $top, $skiptoken, $inlinecount und $select.

So kann man mit $filter nur die für eine aktuell relevanten Entitäten abfragen. Als Beispiel würde ein Lesen per GET auf ../OData.svc/Cars mit gesetztem $filter=ModelYear eq 2013 nur die Autos aus dem Jahr 2013 liefern.

Mit $expand erreicht man, dass beim Lesen einer Entität noch weitere Daten, die sie referenziert, mitgeschickt werden. Als Beispiel würde ein Lesen per GET auf ../OData.svc/Manufacturers mit gesetztem $expand=Cars nicht nur die Daten des Hersteller, sondern mit der selben Response auch die Daten aller dem Hersteller zugeordneten Fahrzeuge liefern.

Per Service Operations (oder auch Function Imports) kann ein OData-Service zusätzliche Einstiegspunkte anbieten, die sich mit HTTP-GET und HTTP-POST in Verbindung mit Parametern aufrufen lassen. Ein einfaches Beispiel wäre eine Service Operation, um alle Hersteller zu bekommen, die Autos in einer bestimmten Farbe anbieten. Ein GET auf ../OData.svc/GetManufacturerWithCar?color='yellow' würde im Anschluss eine entsprechende Liste von Autos liefern.

Bei Service Operations besteht der Unterschied zwischen HTTP-GET und HTTP-POST lediglich in der Definition, dass nur Service-Operationen ein HTTP-GET ohne Nebeneffekte erlauben sollten. Werden durch die definierten Service Operations Werte verändert, so soll dieser nur per HTTP-POST erreichbar sein und einen Aufruf per HTTP-GET ablehnen. Den Body des HTTP-POST kann eine Service Operation nicht verarbeiten.

Durch das Batch Processing kann man mehrere OData-Operationen in einen einzigen HTTP Request verpacken und zum Abarbeiten an den Server übertragen. Der entsprechende Batch Request besteht aus mehreren lesenden (GET) und/oder schreibenden Operationen (Changesets), die in geordneter Reihenfolge auf dem Server ausgeführt werden. Die schreibenden Operationen wiederum können aus einem oder mehreren POST/PUT/DELETE HTTP Requests bestehen, jedoch kein GET und keine weiteren Changesets enthalten. Beispiele mit komplettem Content gibt es in der OData-Dokumentation.