Was ist JSON-LD?

20.10.2023
Von 
Matthew Tyson ist Java-Entwickler und schreibt unter anderem für unsere US-Schwesterpublikation Infoworld.com.
JSON-LD könnte JSON zum nächsten großen Ding im semantischen Web machen.
JSON ist die Lingua Franca der API-Formate - JSON-LD bietet einen einfachen Einstiegspunkt, um semantische Metadaten hinzuzufügen.
JSON ist die Lingua Franca der API-Formate - JSON-LD bietet einen einfachen Einstiegspunkt, um semantische Metadaten hinzuzufügen.
Foto: Gannvector - shutterstock.com

JSON-LD versucht, das Versprechen von selbstbeschreibenden Hypermedien mit der simplen Vertrautheit von JSON zu vereinen. Dazu erweitert es letzteres um Verknüpfungsinformationen. Das ermöglicht wiederum Entwicklern, gängigen JSON-APIs semantische Informationen hinzuzufügen. In diesem Artikel lesen Sie alles, was Sie über diese leistungsstarke JSON-Erweiterung wissen müssen.

JSON-LD definiert

JSON-LD (JavaScript Object Notation for Linked Data) erweitert das JSON-Format um Verknüpfungsinformationen. Diese Erweiterung hat ein breites Anwendungsspektrum - von Knowlegde-Graphen bis hin zur Suchmaschinenoptimierung. Einer der interessantesten Anwendungsfälle ist dabei die Annäherung JSON-basierter APIs an die ursprüngliche Vision von REST: In dieser sind Hypermedia-Dokumente selbstbeschreibend und erhalten eine lose Kopplung zwischen Server und Client aufrecht.

Eine starke Kopplung von Client und Server ist ein maßgebliches Problem bei gängigen JSON-APIs: Der Client weiß, wo sich die Assets befinden und in welcher Beziehung sie zu den Services stehen. Die (bei JSON übliche) harte Kodierung der URLs schafft dabei einen Schwachpunkt innerhalb der Clients. Das widerspricht wiederum dem REST-Ideal, bei dem die Assets dem Client mitteilen, wo die entsprechenden Informationen zu finden sind.

Aus einer High-Level-Perspektive sorgt JSON-LD auch dafür, dass JSON Bestandteil des semantischen Webs (PDF) - auch bekannt als Web 3.0 - werden kann.

JSON-LD in einer Client-Server-App

Wir konzentrieren uns in diesem Artikel auf die praktische Arbeit mit JSON-LD und erstellen in diesem Zuge eine Anwendung, die das Konzept des semantischen Webs in einem Client-Server-Setup demonstriert.

Um ein Gefühl dafür zu bekommen, wie JSON-LD funktioniert, werden wir eine kleine Client-Server-Anwendung erstellen, die JSON-LD von einem Node.js-Server aus bedient - zusammen mit einer einfachen Benutzeroberfläche, mit der wir in der Struktur navigieren können. Dazu werden wir einen zusammenhängen Datensatz verwenden, der Musik beschreibt. Am Ende soll eine Liste von Alben stehen, die man anklicken kann, um einfache Infos dazu aufzurufen. Auch einzelne Songtitel sind klickbar und geben aus, wer seine Verfasser sind respektive waren. Statt die URL, die die Details zu den Musikalben enthält, fest zu kodieren, verwenden wir JSON-LD, um die URL im JSON selbst als ID zu definieren. Damit entfernen wir uns vom Konzept, eine Nummer für die ID zu verwenden und setzen stattdessen auf den tatsächlichen Speicherort.

Listing 1: Ein einfacher JSON-LD-Endpunkt (server.js)

const express = require('express');

const app = express();

const albumsData = [

{

"@id": "/music/albums/1",

"name": "Abbey Road",

"songs": [

{

"@id": "/music/songs/1",

"name": "Here Comes the Sun",

"songwriters": ["George Harrison"]

}

]

},

{

"@id": "/music/albums/2",

"name": "Let It Be",

"songs": [

{

"@id": "/music/songs/2",

"name": "Let It Be",

"songwriters": ["John Lennon", "Paul McCartney"]

}

]

}

];

// Define a route to serve album data

app.get('/music/albums', (req, res) => {

res.json(albumsData);

});

app.get('/music/albums/:albumId', (req, res) => {

const albumId = req.params.albumId;

const album = albumsData.find(album => album["@id"] === `/music/albums/${albumId}`);

if (album) {

res.json(album);

} else {

res.status(404).json({ error: "Album not found" });

}

});

app.use(express.static('public'));

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {

console.log(`Server is running on port ${PORT}`);

});

Die Daten, die der Endpunkt ausgibt, sind typisches JSON - mit dem Unterschied, dass sie die @id-Property aufweisen. Eigenschaften, die mit dem @-Symbol beginnen, sind JSON-LD-spezifisch. In diesem Fall stellen wir einen tatsächlichen Link bereit, den der Client verwenden kann.

In einer typischen JSON-API hätten wir ein ID-Feld und eine ganze Zahl als Wert. Dann würde der Client eine URL auf der Grundlage dieser ID bilden. In diesem Fall kann der Client das ID-Feld so verwenden, wie es ist. Der Server behandelt solche URLs entsprechend im Endpunkt /music/albums/:albumId. Ein einfacher Client für diese API würde wie folgt aussehen.

Listing 2: Ein einfacher JSON-LD_Client (public/index.html)

<!DOCTYPE html>

<html>

<head>

<title>JSON-LD Client</title>

</head>

<body>

<h1>Albums</h1>

<ul id="album-list"></ul>

<div id="album-details"></div>

<script>

const albumList = document.getElementById("album-list");

const albumDetails = document.getElementById("album-details");

// Function to fetch and display albums

function fetchAlbums() {

fetch("/music/albums")

.then(response => response.json())

.then(albums => {

albums.forEach(album => {

const listItem = document.createElement("li");

listItem.innerHTML = `<a href="#" data-album-id="${album["@id"]}">${album.name}</a>`;

albumList.appendChild(listItem);

});

});

}

// Function to fetch and display album details

function fetchAlbumDetails(albumId) {

fetch(albumId)

.then(response => response.json())

.then(album => {

const albumInfo = `

<h2>${album.name}</h2>

<h3>Songs</h3>

<ul>

${album.songs.map(song => `<li><a href="#" data-song-id="${song["@id"]}">${song.nam e}</a></li>`).join("")}

</ul>

`;

albumDetails.innerHTML = albumInfo;

});

}

// Event listener for album links

albumList.addEventListener("click", (event) => {

if (event.target.tagName === "A") {

const albumId = event.target.getAttribute("data-album-id");

fetchAlbumDetails(albumId);

}

});

// Event listener for song links

albumDetails.addEventListener("click", (event) => {

if (event.target.tagName === "A") {

const songId = event.target.getAttribute("data-song-id");

alert("You clicked on song with ID: " + songId);

}

});

// Initialize the client by fetching and displaying albums

fetchAlbums();

</script>

</body>

</html>

Hierbei handelt es sich um ein stark vereinfachtes Beispiel, das einen wesentlichen Punkt hervorheben soll: Der Client kann mit den Links auf generische Art und Weise umgehen, einfach indem er Fetch Requests an die @id-Felder stellt. Das ist ein erster Schritt in Richtung generalisierte Clients, die die Struktur der Service-API nicht kennen müssen.

@Context und @Type

JSON-LD hat noch weit mehr zu bieten - etwa die @context- und @type-Felder. Es gibt mehrere öffentliche Repositories für Kontext- und Typinformationen, die Sie verwenden können, beispielsweise:

Die Grundidee der Felder: Das JSON-Dokument kann seinen Inhalt in einem universell auffindbaren Format beschreiben.

  • Die Eigenschaft @context definiert den Namespace für das Dokument. Sie dient als Zuordnung zwischen den im Dokument verwendeten Begriffen und ihren Definitionen, wodurch die Bedeutung der Daten für Mensch und Maschine klarer wird.

  • Mit der Eigenschaft @type lässt sich der Typ für die Entitäten oder Datenelemente definieren. Dieser Typ hilft dabei, die Daten zu kategorisieren, so dass sie leichter zu interpretieren sind.

Im Folgenden sehen Sie, wie man den schema.org @context und Definitionen wie den MusicComposition-@type verwendet.

Listing 3: @context and @type einsetzen

const albumsData = [

{

"@context": {

"music": "http://schema.org/",

},

"@type": "music:MusicAlbum",

"@id": "/music/albums/1",

"name": "Abbey Road",

"songs": [

{

"@type": "music:MusicComposition",

"@id": "/music/songs/1",

"name": "Here Comes the Sun",

"songwriters": [

{

"@type": "music:MusicGroup",

"name": "The Beatles",

}

]

}

]

},

{

"@context": {

"music": "http://schema.org/",

},

"@type": "music:MusicAlbum",

"@id": "/music/albums/2",

"name": "Let It Be",

"songs": [

{

"@type": "music:MusicComposition",

"@id": "/music/songs/2",

"name": "Let It Be",

"songwriters": [

{

"@type": "music:MusicGroup",

"name": "The Beatles",

}

]

}

]

}

];

Wir haben die auf schema.org bereitgestellte Definition verwendet und ihr den Namen "music" gegeben. Die Definition dient als Namespace, wenn den Datenelementen Typen zugewiesen werden - in diesem Fall music:MusicComposition und music:MusicGroup. Der Client kann nun die @context- und @type-Daten verwenden.

In Bezug auf @type sollte man auch die Begriffe "expand" und "compact" erwähnen:

  • Expand ermöglicht eine ausführlichere Ansicht,

  • während compact für eine kompaktere Syntax sorgt.

Bibliotheken wie jsonls.js unterstützen diese und weitere Operationen, etwa die Konvertierung in das RDF-Format.

Dieser Beitrag basiert auf einem Artikel unserer US-Schwesterpublikation Infoworld.