JSON:API
JSON:API is a core module that serves site content as JSON at ready-made addresses. It is needed when another program reads Drupal data: a mobile app, a React or Vue interface, a neighbouring site. No code is required — it is enough to enable the module.
Enabling
vendor/bin/drush en jsonapiThe module creates addresses for every entity type of the site by itself. No files in the blog module are needed for this.
The list of articles
The address of a collection follows the rule /jsonapi/entity_type/bundle:
curl -g "http://127.0.0.1:8888/jsonapi/node/article"The same address can be opened in a browser. The response is JSON with the list of articles:
{
"data": [
{
"type": "node--article",
"id": "3f0c6a1e-8a53-4b0a-9c1d-2f6d0e7b4a11",
"attributes": {
"title": "First article",
"status": true,
"created": "2026-03-01T10:00:00+00:00"
},
"relationships": {
"field_tags": { "data": [] }
}
}
],
"links": {
"self": { "href": "http://127.0.0.1:8888/jsonapi/node/article" }
}
}Ordinary fields are in attributes, references to other entities in relationships. The id here is not the node number but a UUID: a long unique identifier every entity has.
One article
curl -g "http://127.0.0.1:8888/jsonapi/node/article/3f0c6a1e-8a53-4b0a-9c1d-2f6d0e7b4a11"The UUID from the list goes at the end of the address. The response holds a single object in data.
Query parameters
| Parameter | What it does |
|---|---|
filter[status]=1 | Keeps the records with this field value |
sort=-created | Sorts; a minus means descending |
page[limit]=5 | Limits the count |
page[offset]=5 | Skips the first records |
fields[node--article]=title,created | Returns only the listed fields |
include=field_tags | Adds the referenced entities to the response |
Parameters are joined with &:
curl -g "http://127.0.0.1:8888/jsonapi/node/article?sort=-created&page[limit]=5&fields[node--article]=title,created"The request returns the five latest articles with only the title and the date. The -g switch tells curl not to interpret the square brackets in its own way.
Access
JSON:API respects the same permissions as the site. An anonymous visitor gets only published articles and only with the "View published content" permission. Unpublished nodes and restricted fields do not get into the response.
Writing
By default the module is read-only. Creating, updating and deleting are enabled at Configuration → Web services → JSON:API, the address /admin/config/services/jsonapi. After that POST, PATCH and DELETE requests work for users with the right permissions; the request must be authenticated — for example through the core HTTP Basic Authentication module.
Your own JSON address
If you need a response with your own structure rather than the whole node, an ordinary route and a controller returning JsonResponse will do — it is shown in the lesson about controllers. Choose JSON:API for standard operations on entities and your own controller for a special response.
Common mistake
A JSON:API address uses the UUID, not the node number: /jsonapi/node/article/5 returns 404. You can find the UUID in the collection response or in code — $node->uuid(). To get a node by its number, use a filter: /jsonapi/node/article?filter[drupal_internal__nid]=5.