Core architecture
Core Architecture
When to Use
Understanding the architecture is essential when customizing JSON:API behavior, debugging issues, or extending functionality.
Decision
| Task | Component | Location |
|---|---|---|
| Understand entity to JSON transformation | ResourceObjectNormalizer | core/modules/jsonapi/src/Normalizer/ |
| Discover available resources | ResourceTypeRepository | core/modules/jsonapi/src/ResourceType/ |
| Handle CRUD operations | EntityResource controller | core/modules/jsonapi/src/Controller/ |
| Parse filter/sort queries | Query system | core/modules/jsonapi/src/Query/ |
| Customize resource types | ResourceTypeBuildEvent | core/modules/jsonapi/src/ResourceType/ |
| Apply field transformations | Field enhancers (Extras) | modules/contrib/jsonapi_extras/src/Plugin/ |
Pattern
Resource type discovery flow:
// 1. Repository discovers all entity types/bundles
$repository = \Drupal::service('jsonapi.resource_type.repository');
// 2. Get specific resource type
$resource_type = $repository->get('node', 'article');
// 3. Access resource type information
$type_name = $resource_type->getTypeName(); // "node--article"
$fields = $resource_type->getFields();
$public_name = $resource_type->getPublicName('field_image'); // "field_image"
Normalization flow:
// 1. Entity loads
$entity = Node::load(1);
// 2. ResourceObjectNormalizer transforms to JSON:API
$normalizer = \Drupal::service('serializer.normalizer.resource_object');
$normalized = $normalizer->normalize($entity, 'api_json');
// 3. Result: { type, id, attributes, relationships }
Key Components
ResourceType System:
- ResourceType: Represents entity type + bundle configuration
- ResourceTypeRepository: Discovers entities, generates ResourceType objects, caches
- ResourceTypeBuildEvent: Allows modules to alter resource types (used by JSON:API Extras)
Normalization System:
- JsonApiDocumentTopLevelNormalizer: Top-level document with data/links/meta/included
- ResourceObjectNormalizer: Individual resource objects, attributes/relationships separation
- FieldItemNormalizer: Field-level value normalization
Controller System:
- EntityResource: Handles GET, POST, PATCH, DELETE via getIndividual(), getCollection(), createIndividual(), patchIndividual(), deleteIndividual()
- FileUpload: Binary file uploads to entity fields
Query System:
- Filter: Parses filter parameters, supports 14 operators
- Sort: Parses sort parameters, multiple fields, asc/desc
- OffsetPage: Pagination with offset/limit, link generation
Common Mistakes
Modifying core normalizers directly: Never edit core files. WHY: Updates overwrite changes. Instead, create decorating normalizers with higher priority in services.yml.
Not clearing cache after resource type changes: Resource types are cached. WHY: Performance optimization. Run drush cache:rebuild after altering resource types.
Assuming field names match API names: JSON:API Extras can rename fields. WHY: field_publication_date might be exposed as published_at. Always use ResourceType::getPublicName() and getInternalName().