Daten exponieren mit OData und Apache Olingo

CRUD

Alle Beziehungen einer Entity zu anderen werden ebenso als URIs speziell über die Navigation Property gelistet. Dadurch ist es möglich, von einer Entität direkt auf von ihr referenzierte Entitäten zu navigieren.

Der OData-Standard unterstützt AtomPub und JSON als Austauschformat der Daten. Als Standard ist AtomPub definiert (Accept-Header: application/atom+xml). JSON lässt sich mit speziellen Aufrufparametern beim Service anfordern (entweder per Accept-Header: application/json oder $format=json).

Beim Anlegen und/oder Modifizieren von Daten gilt AtomPub (Content-Type: application/atom+xml) als Standard, JSON lässt sich zudem angeben (Content-Type: application/json).

Basic CRUD

Für das Anlegen einer Entität wird ein HTTP-POST mit entsprechendem Content im HTTP BODY und korrekt gesetztem Content-Type HTTP Header auf die URI des EntitySet durchgeführt (REST-Prinzipien). Im aktuellen Beispiel wäre das ein POST auf die URI ../OData.svc/Cars mit Content-Type=application/atom+xml und folgendem Content im Body:

HTTP-POST Request Body:

<?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>CarModel</d:Model>
<d:Price>47110</d:Price>
<d:ModelYear>2014</d:ModelYear>
</m:properties>
</content>
</entry>

Der Aufruf liefert (entsprechend dem gesetzten Accept Header) die Daten der angelegten Entität zurück. Anhand der in dem Beispielservice angelegten Entität kann man sehen, dass es möglich ist, bestimmte Property-Felder beim Anlegen leer zu lassen, die im Anschluss vom Service nach den im EDM festgelegten Standardwerten befüllt werden. Erwähnenswert ist zudem, dass das Key-Property-Feld, im Beispiel die Id, beim POST nicht mitgeschickt wurde. Es liegt im Ermessen des Service, wie damit umgegangen wird.

Das Standardvorgehen für OData-Services ist, dass der Service die Key-Property-Felder beim Anlegen einer Entität entsprechen befüllt. Hierbei ist es sogar so, dass mitgeschickte Key-Property-Werte vom Service ignoriert werden können und dieser die Key-Property-Werte generiert. In der zurückgelieferten Entität sind die entsprechenden Felder dann so befüllt, wie sie vom Service verarbeitet und gegebenenfalls persistiert wurden.

HTTP-POST Response Body:

<?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/">
<id>http://localhost:8080/MyFormula.svc/Cars('6')</id>
<title type="text">Cars</title>
<updated>2014-01-28T08:17:23.363+01:00</updated>
<category term="MyFormula.Car" scheme="http://schemas.microsoft.com↩
/ado/2007/08/dataservices/scheme"/>
<link href="Cars('6')" rel="edit" title="Car"/>
<link href="Cars('6')/Manufacturer"
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related↩
/Manufacturer"
title="Manufacturer" type="application/atom+xml;type=entry"/>
<link href="Cars('6')/Driver"
rel="http://schemas.microsoft.com/ado/2007/08/dataservice/related↩
/Driver"
title="Driver" type="application/atom+xml;type=entry"/>
<content type="application/xml">
<m:properties>
<d:Id>6</d:Id>
<d:Model>CarModel</d:Model>
<d:Price>47110.0</d:Price>
<d:ModelYear>2014</d:ModelYear>
<d:Updated m:null="true"/>
</m:properties>
</content>
</entry>

Lesend zugreifen

Für das Lesen von Entitäten gibt es zwei wesentliche Möglichkeiten. Eine angelegte Entität lässt sich durch ihre eindeutige URI direkt referenzieren und somit lesen. Alternativ kann der Feed für eine Entität über ein zuvor per EDM definiertes EntitySet (Collection) referenziert werden. In der Folge lassen sich alle bekannten Entitäten lesen.

Technisch bedeutet das Lesen ein HTTP-GET auf die URI. Durch das Setzen des Accept HTTP Header lässt sich das gelieferte Format beeinflussen. Im aktuellen Beispiel wäre das ein GET auf die URI ../OData.svc/Cars mit Accept: application/atom+xml um alle Autos zu bekommen, was im in Listing gezeigten Response Body resultiert. Ein GET auf die URI eines Autos ../OData.svc /Cars('1') mit Accept: application/atom+xml, um das Auto mit dem Key von 1 zu bekommen, erzeugt hingegen:

HTTP-GET Response Body:

<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/">
<id>http://localhost:8080/MyFormula.svc/Cars('1')</id>
<title type="text">Cars</title>
<updated>2014-01-30T10:15:36.237+01:00</updated>
<category term="MyFormula.Car" scheme="http://schemas.microsoft.com↩
/ado/2007/08/dataservices/scheme"/>
<link href="Cars('1')" rel="edit" title="Car"/>
<link href="Cars('1')/Manufacturer" rel="http://schemas.microsoft.com↩
/ado/2007/08/dataservices/related/Manufacturer" title="Manufacturer"
type="application/atom+xml;type=entry"/>
<link href="Cars('1')/Driver" rel="http://schemas.microsoft.com↩
/ado/2007/08/dataservices/related/Driver" title="Driver"
type="application/atom+xml;type=entry"/>
<content type="application/xml">
<m:properties>
<d:Id>1</d:Id>
<d:Model>F1 W02</d:Model>
<d:Price>167189.0</d:Price>
<d:ModelYear>2011</d:ModelYear>
<d:Updated>2014-01-30T09:13:34.847</d:Updated>
</m:properties>
</content>
</entry>

Darüber hinaus lassen sich Property-Felder von Entitäten direkt referenzieren und somit lesen (entsprechend den REST-Prinzpien).

Daten aktualisieren

Für ein Update der Daten einer Entität gibt es unterschiedliche Möglichkeiten. Die wichtigsten sind HTTP-PUT und HTTP-PATCH / HTTP-MERGE auf die eindeutige URI (etwa ../OData.svc/Car('1')) einer Entität, mit entsprechendem Content im HTTP BODY und korrekt gesetztem Content-Type HTTP Header (REST-Prinzipien).

Bei einem HTTP-PUT auf die eindeutige URI einer Entität werden alle im Request Body gesendeten Property-Felder gelesen und entsprechend bei der Entität aktualisiert. Nicht im Request-Body mitgeschickte Felder interpretiert das System als NULL und löscht sie bei der entsprechenden Entität (beziehungsweise setzt es sie auf m:null=true).