logo

Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll
04/09/2025, by Ivan

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: errorsmetalinks, 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 relationshipsattributes 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 een Term 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.