//

JSON-LD: Verlinkte Daten statt hart-kodierter Endpunkte

10.7.2018 | 3 Minuten Lesezeit

Mit JSON-LD können Abhängigkeiten zwischen Frontend und Backend reduziert werden. Im letzten Artikel habe ich gezeigt, wie sich die JSON-Bezeichner entkoppeln lassen. Als nächstes lernst du, wie ein Frontend Daten laden kann, ohne abhängig von bestimmten Endpunkten im Backend zu sein. Das Laden von Daten wird zum einen deutlich vereinfacht, zum anderen bleibt das Frontend stabiler gegenüber Änderungen im Backend.

Als Beispiel dient wieder ein Datensatz über eine Person:

1{
2    "id": "42",
3    "firstname": "John",
4    "lastname": "Doe",
5    "address_id": "1337" 
6}
7

Offenbar ist zu dieser Person auch eine Adresse unter der ID 1337 hinterlegt. Um diese Annahme zu bestätigen ist ein Blick in die API-Dokumentation nötig. Dort erfährt das Frontend-Team dann (hoffentlich) auch, wie genau die Adresse geladen werden kann. Ein URL-Template wie https://api.example/addresses/ wird dann oft fest im Code verdrahtet.

Mit JSON-LD verfolgen wir einen anderen Ansatz. Wie im letzten Artikel erwähnt, steht das „LD“ in JSON-LD für „Linked Data“ . Statt nur lokal gültiger IDs verwenden wir global eindeutige, dereferenzierbare URIs, um Ressourcen im Web zu identifizieren. Die ID eines JSON-LD-Datensatzes ist immer ein vollständiger, internationalisierter URI (im Folgenden IRI : Internationalized Resource Identifier). Um den obigen Datensatz als JSON-LD abzubilden, fügen wir wieder einen Kontext hinzu:

1{
2  "@context": {
3    "@vocab": "https://schema.org/",
4    "@base": "https://api.example/",
5    "firstname": "givenName",
6    "lastname": "familyName",
7    "id": "@id",
8    "address_id": {
9      "@id": "address",
10      "@type": "@id"
11    }
12  },
13  "id": "persons/42",
14  "firstname": "John",
15  "lastname": "Doe",
16  "address_id": "addresses/1337"
17}
18

Wie bereits im letzten Artikel bilden wir die vom Backend verwendeten JSON-Bezeichner auf das Vokabular von schema.org ab. Hinter firstname steckt also wieder ein https://schema.org/givenName und hinter lastname entsprechend ein https://schema.org/familyName. Bei address_id verwenden wir eine etwas komplexere Konfiguration. Zunächst legen wir mit "@id": "address" fest, dass es sich um eine https://schema.org/address handelt. Mit "@type": "@id" sagen wir zusätzlich, dass wir nur die ID der Adresse hinterlegt haben und kein komplettes Adress-Objekt.

An den Daten selbst hat sich diesmal eine Kleinigkeit geändert: Statt „42“ und „1337“ hinterlegen wir die relativen Pfade persons/42 und addresses/1337. Zusammen mit dem im Kontext unter @base hinterlegten Basis-IRI ergibt sich für die Adresse der vollständige IRI https://api.example/addresses/1337.

Im Frontend verwenden wir wieder einen eigenen Kontext und legen so die lokalen Bezeichner für die schema.org Eigenschaften fest:

1const context = {
2  "@vocab": "https://schema.org/",
3  "first_name": "givenName",
4  "last_name": "familyName",
5  "postal_address": "address",
6  "iri": "@id"
7}
8

Indem wir den Frontend-Kontext anwenden, erhalten wir folgendes Objekt:

1var person = {
2  "@context": { /** ... */ },
3  "iri": "https://api.example/persons/42",
4  "postal_address": {
5    "iri": "https://api.example/addresses/1337"
6  },
7  "last_name": "Doe",
8  "first_name": "John"
9}
10

Hier sehen wir nun leicht, wie wir die Adresse nachladen können, nämlich einfach von person.postal_address.iri. Es ist nicht nötig, vorab im Frontend einen Endpunkt für Adressen zu kennen und die ID korrekt in ein URL-Template oder Ähnliches einzubauen. Stattdessen können wir eine generische Ladelogik implementieren:

1jsonld.compact(personDataFromBackend, context, (err, person) => {
2  loadData(person.postal_address);
3});
4 
5function loadData(resource) {
6    console.log(`Loading ${resource.iri}`);
7    // do http request ...
8}
9

Gegenüber Änderungen des IRI ist das Frontend immun. Ändert dieser sich zum Beispiel zu https://api.example/person/42/address sind keine Anpassungen im Frontend nötig. Das Backend liefert dann "address_id": "person/42/address" und die Ladelogik funktioniert wie gehabt.

Selbst wenn sich das Backend-Team entscheidet, zusätzlich zur ID einige Adressdaten vorab mit zu senden, ändert sich im Frontend nichts. Lediglich das Backend ändert Daten und Kontext wie folgt:

1{
2  "@context": {
3    "@vocab": "https://schema.org/",
4    "@base": "https://api.example/",
5    "firstname": "givenName",
6    "lastname": "familyName",
7    "street": "streetAddress",
8    "id": "@id"
9  },
10  "id": "persons/42",
11  "firstname": "John",
12  "lastname": "Doe",
13  "address": {
14    "@id": "addresses/1337",
15    "street": "Mainstreet 23"
16  }
17}
18

An der Semantik der Daten hat sich nichts geändert hat, daher funktioniert das Frontend wie gehabt weiter. Das Backend liefert ja weiterhin die ID der Adresse aus. Die hinzu gekommene https://schema.org/streetAddress können, aber müssen wir im Frontend nicht nutzen. Es ist aber generell empfehlenswert, das Frontend so zu implementieren, dass mitgelieferte Daten bereits verwendet werden, bis der Ladevorgang von ggf. zusätzlichen Daten abgeschlossen ist.

Wie wir sehen, gibt es mit JSON-LD keinen Grund mehr, „Endpunkte“ im Frontend hart zu kodieren. IDs werden zu abrufbaren IRIs – JSON wird zu Linked Data . In dieser Form werden Daten auch unabhängig von einer bestimmten JSON-Struktur und -Verschachtelung. Dies werde ich im nächsten Artikel näher beleuchten.

Ich habe auch wieder ein JSFiddle mit dem Beispiel aus diesem Artikel vorbereitet:

Weiter mit „Linked Data mit JSON-LD: Semantische Fakten statt fester Baumstruktur“

Beitrag teilen

Gefällt mir

0

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen

Wir helfen Deinem Unternehmen

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.