Extending JSON:API
JSON:API mirrors your content model automatically, which is convenient until the raw field names (field_hero_image, body) leak into a public API contract. This guide reshapes the exposed surface, renaming and hiding fields, without changing the entities themselves.
Control the public shape of JSON:API resources: rename fields to a stable public name, hide internal fields, or add computed data. Do this in Drupal so every consumer sees the same contract; do not paper over raw field names in each front end. For read patterns (filtering, includes), see JSON:API basics and relationships and writes first.
Prerequisites
Section titled “Prerequisites”- A custom module, per Scaffold a module.
- The core JSON:API module (
drush pm:install jsonapi). - The Article content model from JSON:API basics, which the examples rename fields on.
- Services and events for the event subscriber.
Rename or hide fields with the build event
Section titled “Rename or hide fields with the build event”JSON:API fires a ResourceTypeBuildEvent as it assembles each resource type. An event subscriber can rename a field’s public name or disable it entirely. This subscriber renames the article title field to headline.
<?php
declare(strict_types=1);
namespace Drupal\howto_jsonapi\EventSubscriber;
use Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent;use Drupal\jsonapi\ResourceType\ResourceTypeBuildEvents;use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/** * Reshapes the article JSON:API resource as it is built. * * JSON:API mirrors your content model automatically, but you rarely want * the raw field names on a public API. Subscribe to the resource-type * build event to rename or hide fields without touching the entity. */final class ArticleHeadlineSubscriber implements EventSubscriberInterface {
/** * {@inheritdoc} */ public static function getSubscribedEvents(): array { return [ResourceTypeBuildEvents::BUILD => 'onBuild']; }
/** * Renames the article title field to "headline" on the public API. */ public function onBuild(ResourceTypeBuildEvent $event): void { if ($event->getResourceTypeName() !== 'node--article') { return; } foreach ($event->getFields() as $field) { if ($field->getInternalName() === 'title') { $event->setPublicFieldName($field, 'headline'); } } }
}setPublicFieldName() changes how the field appears in API responses and in filter/sort/include query parameters; disableField() removes it from the API surface completely. The entity, its storage, and the admin UI are untouched.
Verify
Section titled “Verify”After installing the module, the renamed field appears in the resource type:
ddev drush pm:install howto_jsonapiddev drush php:eval " \$rt = \Drupal::service('jsonapi.resource_type.repository')->get('node', 'article'); echo \$rt->getPublicName('title');"prints headline. A request to /jsonapi/node/article then exposes the title under attributes.headline, and ?sort=headline works. The module’s kernel test asserts the rename and that other bundles keep the original name.
Variations
Section titled “Variations”Computed fields
Section titled “Computed fields”To expose data that is not a stored field, add a computed base field to the entity with hook_entity_base_field_info() and a field class that calculates its value. JSON:API exposes computed fields like any other, so a “reading time” or “full URL” attribute needs no JSON:API-specific code.
Custom routes
Section titled “Custom routes”When a consumer needs a shape JSON:API cannot express, a controller returning JSON alongside JSON:API is simpler than bending the spec. Reserve it for genuinely custom endpoints.
Related
Section titled “Related”- JSON:API basics and relationships and writes for consuming the API.
- Services and events for the event subscriber pattern.
- The
JSON:API architecture topicon api.drupal.org.
Was this page helpful?
Drupal is a registered trademark of Dries Buytaert.