Problem/Motivation
As I was working on various issues to make the config schema for field_storage_config be exposed via this wonderful module (see #3324769: Schema incorrect for config entity types with multi-part IDs (field_storage_config, field_config, entity_view_mode, entity_form_mode, entity_view_display and entity_form_display) + #3324824: Schema incorrect for config entity "fields" that are Maps and Sequences), specifically for https://www.drupal.org/project/field_ui_modern, I discovered/realized that there is a lot left to be explored WRT JSON Schema and specifically the validation aspects of it, which are covered by https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validati....
This module already exposes things like required, but rarely more than that. Ideally, we should be able to automatically transform both content entity validation constraints and config schema types + validation constraints (see #2164373: [META] Untie config validation from form validation — enables validatable Recipes, decoupled admin UIs …).
Relates issues but with a narrower scope: #3058852: Ensure valid "type" values for JSON data types, #3174991: Include all bundles in the enum for entity_reference fields and #3258702: Properly handle nullable values
P.S.: I thought https://modern-json-schema.com/json-schema-is-a-constraint-system was a particularly good high-level introduction.
Steps to reproduce
Proposed resolution
Generate a far richer schema, somewhat like this — note the use of:
uniqueItemsexclusiveMinimumrequiredenum$drupalUiHint→ Drupal-specific addition!$drupalPluginIdOfType→ Drupal-specific addition!
{
"$schema": "https://json-schema.org/draft/2019-09/hyper-schema",
"$id": "/jsonapi/field_storage_config/field_storage_config/resource/schema",
"title": "Field storage",
"allOf": [
{
"type": "object",
"properties": {
"type": {
"$ref": "#/definitions/type"
},
"attributes": {
"$ref": "#/definitions/attributes"
}
}
},
{
"$ref": "https://jsonapi.org/schema#/definitions/resource"
}
],
"definitions": {
"type": {
"const": "field_storage_config--field_storage_config"
},
"attributes": {
"type": "object",
"description": "Entity attributes",
"required": [
"entity_type",
"field_name",
"field_storage_config_type"
],
"properties": {
"uuid": {
"type": "string",
"title": "UUID",
"format": "uuid",
"maxLength": 128,
"$drupalUiHint": "no-ui"
},
"drupal_internal__id": {
"type": "string",
"title": "drupal_internal__id",
"pattern": "^(node|media|taxonomy_term|user)\\.[_a-z]+[_a-z0-9]*$",
"$comment": "The ID consists of 2 parts: the entity type and the field name."
},
"field_name": {
"type": "string",
"title": "Field name",
"pattern": "^[_a-z]+[_a-z0-9]*$",
"description": "The name of the field."
},
"entity_type": {
"type": "string",
"title": "Entity Type",
"enum": [
"node",
"media",
"taxonomy_term",
"user"
],
"$drupalPluginIdOfType": "content_entity_type",
"$drupalUiHint": "dropdown"
},
"field_storage_config_type": {
"type": "string",
"title": "Field type",
"$comment": "Tricky: This is only not called 'type' because that is a reserved keyword in JSON:API.",
"description": "Choose a field type.",
"enum": [
"uuid",
"boolean",
"decimal",
"email",
"entity_reference",
"float",
"integer",
"string",
"string_long",
"timestamp",
"comment",
"datetime",
"daterange"
],
"$drupalPluginIdOfType": "field_type",
"$drupalUiHint": "dropdown"
},
"langcode": {
"type": "string",
"title": "Language",
"enum": ["en"],
"default": "en",
"$drupalUiHint": "no-ui"
},
"status": {
"type": "boolean",
"title": "Status",
"default": true
},
"dependencies": {
"type": "object",
"title": "Dependencies",
"$drupalUiHint": "no-ui",
"additionalProperties": false,
"properties": {
"config": {
"type": "array",
"uniqueItems": true,
"title": "Configuration dependencies",
"items": {
"type": "string",
"title": "Configuration dependency"
}
},
"content": {
"type": "array",
"uniqueItems": true,
"title": "Content dependencies",
"items": {
"type": "string",
"title": "Content dependency"
}
},
"module": {
"type": "array",
"uniqueItems": true,
"title": "Module dependencies",
"items": {
"type": "string",
"title": "Module dependency"
}
},
"theme": {
"type": "array",
"uniqueItems": true,
"title": "Theme dependencies",
"items": {
"type": "string",
"title": "Theme dependency"
}
}
},
"enforced": {
"type": "object",
"title": "Enforced dependencies",
"additionalProperties": false,
"properties": {
"config": {
"type": "array",
"uniqueItems": true,
"title": "Configuration dependencies",
"items": {
"type": "string",
"title": "Configuration dependency"
}
},
"content": {
"type": "array",
"uniqueItems": true,
"title": "Content dependencies",
"items": {
"type": "string",
"title": "Content dependency"
}
},
"module": {
"type": "array",
"uniqueItems": true,
"title": "Module dependencies",
"items": {
"type": "string",
"title": "Module dependency"
}
},
"theme": {
"type": "array",
"uniqueItems": true,
"title": "Theme dependencies",
"items": {
"type": "string",
"title": "Theme dependency"
}
}
}
}
},
"third_party_settings": {
"type": "array",
"items": {
"properties": {
"third_party_settings": {
"title": "third_party_settings"
}
}
}
},
"locked": {
"type": "boolean",
"title": "Locked",
"description": "Whether the field storage is locked or not. When locked, field settings cannot be changed, no new fields can be created using this storage, and existing fields using this storage cannot be deleted.",
"default": false,
"$drupalUiHint": "no-ui-when-creating"
},
"cardinality": {
"type": "integer",
"title": "Cardinality",
"description": "Allowed number of values",
"exclusiveMinimum": 1,
"default": 1
},
"translatable": {
"type": "boolean",
"title": "Translatable",
"default": true
},
"indexes": {
"type": "array",
"$drupalUiHint": "no-ui",
"items": {
"properties": {
"indexes": {
"title": "indexes"
}
}
}
},
"persist_with_no_fields": {
"type": "boolean",
"title": "Whether the field storage should be persisted when orphaned",
"default": false,
"$drupalUiHint": "no-ui"
},
"custom_storage": {
"type": "boolean",
"title": "custom_storage",
"default": false,
"$drupalUiHint": "no-ui"
}
},
"additionalProperties": false
}
}
}
Remaining tasks
TBD
User interface changes
TBD
API changes
TBD
Data model changes
TBD
| Comment | File | Size | Author |
|---|---|---|---|
| #2 | EXPLORATION-jsonapi_schema_config_validation-3324982-2.patch | 9.02 KB | wim leers |
Comments
Comment #2
wim leersComment #3
wim leersMentioned this over at #2164373-31: [META] Untie config validation from form validation — enables validatable Recipes, decoupled admin UIs ….
Comment #4
wim leersComment #5
m.stentaWe have automated tests now (#3257911: Add basic test coverage) so it would be good to include a test to demonstrate this issue and prevent regressions.