Kernconcepten
JSON:API heeft veel concepten in de specificatie, die hier niet allemaal gedocumenteerd zijn. Gebruikers van de module hoeven echter niet alle concepten van de specificatie volledig te begrijpen om productief te kunnen werken met deze module. Als je wƩl dieper wilt ingaan op hoe de documenten van JSON:API zijn opgebouwd, waarom de module iets op een bepaalde manier doet, of gewoon meer wilt leren over het ontwerp van de module, dan worden lezers aangemoedigd om de specificatie te lezen op jsonapi.org.
Documentstructuur
JSON:API is zeer uitgesproken over hoe JSON-documenten moeten worden opgebouwd en welke informatie in elk request- en/of response-body moet staan.
Elk request/response-body moet onder ƩƩn enkel JSON-object vallen.
{
// je data hier...
}
De data, of de informatie die specifiek is voor een resource of meerdere resources, moet binnen dit top-level object leven onder het data
āmemberā. Een āmemberā is gewoon een vooraf gedefinieerde key in het JSON-object. Het data
member kan ofwel een object ({}
) zijn of een array ([]
). Bij het aanmaken of bijwerken van een resource zal dit altijd een enkel object ({}
) zijn dat een enkel item voorstelt. Alleen bij het ophalen van een ācollectieā van meerdere resources zal deze property een array zijn.
{
"data": {
// Je resource data komt hier.
}
}
Andere top-level members zijn: errors
, meta
, links
, en included
. Hiervan zal included
het vaakst worden gebruikt, maar dit wordt later in de documentatie behandeld.
Voor meer informatie over de top-level structuur kun je de specificatie raadplegen.
Binnen de data
- en included
-members staan āresource objectsā of āresource identifier objectsā. āResource objectsā vertegenwoordigen de inhoud van de resources (entiteiten) waar je mee werkt. āResource identifier objectsā zijn zoals foreign keys in een database; ze identificeren een resource zonder de velden van die resource te bevatten. In Drupal-termen is een resource object meestal de JSON-representatie van een enkele entiteit, dat kan een node zijn, een taxonomieterm of een gebruiker. In Drupal-termen is een resource identifier gewoon genoeg informatie om een entiteit te ladenāje hebt het type en het ID, en niets meer.
Elk resource object moet twee members bevatten: type
en id
. De enige uitzondering hierop is bij het aanmaken van een nieuwe entiteit, in dat geval mag het id
worden weggelaten om Drupal een id te laten genereren voor de nieuwe resource. Het is echter volledig mogelijk dat de clientapplicatie een UUID aan de resource meegeeft bij het aanmaken van een nieuwe entiteit. Alle IDās in JSON:API zijn UUIDās.
Het type
member is altijd verplicht. De waarde voor het type-member is afgeleid van de naam van het entiteitstype en de bundle, waar van toepassing. Het type voor een entiteitsresource volgt altijd het patroon entity_type--bundle
. Bijvoorbeeld: de core node-typen article en basic page worden weergegeven als: node--article
en node--page
.
Dus, op een entiteit zonder verplichte eigenschappen of velden, kan men een nieuwe entiteit aanmaken met de volgende JSON:
{
"data": {
"type": "node--my-bundle",
}
}
Dit zou echter niet erg nuttig zijn. We moeten echte waarden voor de entiteit opnemen. Om dit te doen heeft JSON:API twee members voor waarden: attributes
en relationships
. attributes
slaan waarden op die specifiek zijn voor de onderliggende resource. relationships
zijn waarden die behoren tot een andere resource in het systeem. In Drupal-termen vertegenwoordigen relationships
meestal waarden die worden opgeslagen door een entiteitsreferentie. Op de core article-bundle van Drupal kan dit de uid
property zijn. Dit komt omdat de uid
property een entiteitsreferentie is naar de gebruiker die het artikel heeft geschreven. De body van een document met attributes
en relationships
kan er zo uitzien:
{
"data": {
"type": "node--my-bundle",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"title": "Een voorbeeld"
},
"relationships": {
"uid": {
"data": {
"type": "user--user",
"id": "53bb14cc-544a-4cf2-88e8-e9cdd0b6948f"
}
}
}
}
}
Zoals je ziet staat de uid
property onder het relationships
-member. Net als de hoofdresource bevat het ook een type
- en een id
-member, omdat het een aparte en afzonderlijke resource is.
Merk op dat uid
geen attributes
of relationships
heeft. Dit komt omdat JSON:API de inhoud van een relatie niet opneemt tenzij hier expliciet om gevraagd wordt via een speciale queryparameter, include
. Meer hierover later in de documentatie (zie āResources ophalen (GET)ā).
Voor meer details over de structuur van resource objects kun je de specificatie raadplegen.
§ āVirtueleā resource-identificatoren
In sommige omstandigheden staat Drupal toe dat een relatie naar een resource verwijst (een entiteitsreferentie naar een entiteit) die niet in de database is opgeslagen en daarom niet via JSON:API kan worden opgehaald. De āvirtueleā resource-identificator kan verschillende omstandigheden aanduiden afhankelijk van de context, maar verwijst altijd naar een resource die niet kan worden gevonden.
Gebruik en betekenis van de āvirtueleā resource-identificator in Drupal core
Het taxonomietermveld parent
is het meest opvallende voorbeeld van dit speciale geval in Drupal core. Dit relatieveld kan een resource-identificator bevatten voor een āvirtueleā taxonomieterm-resource. In dit geval identificeert de āvirtueleā resource-identificator de <root>
taxonomieterm. Dit geeft aan dat de verwijzende term zich op het hoogste niveau van zijn vocabulaire bevindt.
Bekijk bijvoorbeeld het volgende response-document voor een hypothetische taxonomieterm:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Politiek"
},
"relationships": {
"parent": {
"data": [
{
"id": "virtual",
"type": "taxonomy_term--tags",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#virtual",
"meta": {
"about": "Gebruik en betekenis van de āvirtueleā resource-identificator."
}
}
}
}
}
]
}
}
}
}
Merk op dat de parent
-relatie van deze Term
(een entiteitsreferentieveld) een resource identifier object heeft waarvan het id
geen UUID is, maar "virtual"
. Dit is noodzakelijk omdat een top-level of root-level Term
een verwijzing heeft naar een niet-opgeslagen <root>
-term (target_id = 0)
als ouder.
Waarom?
Aangezien de root-term niet wordt opgeslagen en een Term
meer dan ƩƩn ouder kan hebben, is de cruciale vraag: hoe onderscheiden we een Term
die:
- alleen
Term
3
als ouder heeft ([3]
) ? - zowel deze niet-opgeslagen root
Term
als ouder Ʃn eenTerm
3
([0, 3]
) heeft?
Het antwoord is dat als JSON:API de niet-opgeslagen root-term 0
zou weglaten in plaats van het "virtual"
-ID te gebruiken, het niet mogelijk zou zijn die twee gevallen te onderscheiden!
§ āOntbrekendeā resource-identificatoren
Drupal āruimtā relaties naar verwijderde resources niet op (entiteitsreferentievelden die verwijzingen hebben naar entiteiten die zijn verwijderd). Met andere woorden: Drupal laat āzwevendeā relaties (entiteitsreferenties) staan.
Wanneer JSON:API zulke zwevende relaties tegenkomt, gebruikt het de āontbrekendeā resource-identificator.
Gebruik en betekenis van de āontbrekendeā resource-identificator in Drupal core
Blijvend bij het voorbeeld van de āvirtueleā resource-identificator: het taxonomietermveld parent
. Stel dat een bepaalde taxonomieterm vroeger de taxonomieterm āBelgiĆ«ā als ouder had, maar dat de resource van de taxonomieterm āBelgiĆ«ā nu niet meer bestaat ā misschien omdat het kleine land BelgiĆ« ophield te bestaan. Dan zou dit relatieveld een resource-identificator bevatten voor een āontbrekendeā taxonomieterm-resource.
Bekijk bijvoorbeeld het volgende response-document voor een hypothetische taxonomieterm:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Politiek"
},
"relationships": {
"parent": {
"data": [
{
"id": "missing",
"type": "unknown",
"meta": {
"links": {
"help": {
"href": "https://www.drupal.org/docs/8/modules/json-api/core-concepts#missing",
"meta": {
"about": "Gebruik en betekenis van de āontbrekendeā resource-identificator."
}
}
}
}
}
]
}
}
}
}
Merk op dat de parent
-relatie van deze Term
(een entiteitsreferentieveld) een resource identifier object heeft waarvan het id
geen UUID is, maar "missing"
. Bovendien is het type
unknown
(omdat Drupal de bundle van de verwezen entiteit niet opslaat, alleen het entiteitstype, en dus het bepalen van de JSON:API-resource-typenaam onmogelijk is).
Artikel uit de Drupal-documentatie.