Conceptos básicos
JSON:API tiene muchos conceptos en la especificación, no todos documentados aquí. Sin embargo, los usuarios del módulo no necesitan comprender completamente todos los conceptos de la especificación para ser productivos con este módulo. Si deseas profundizar en cómo se estructuran los documentos JSON:API, por qué el módulo hace las cosas de cierta manera o simplemente quieres aprender más sobre el diseño del módulo, se recomienda leer la especificación en jsonapi.org.
Estructura del Documento
JSON:API es muy estricto respecto a cómo deben estructurarse los documentos JSON y qué información debe incluirse en cada cuerpo de solicitud y/o respuesta.
Todo cuerpo de solicitud/respuesta debe estar bajo un solo objeto JSON.
{
// tus datos aquí...
}
La información específica de un recurso o recursos debe vivir dentro de este objeto de nivel superior bajo el miembro data
. Un “miembro” es simplemente una clave predefinida en el objeto JSON. El miembro data
puede ser un objeto ({}
) o un array ([]
). Al crear o actualizar un recurso, esto siempre será un solo objeto ({}
) representando un único elemento. Solo al recuperar una “colección” de múltiples recursos, esta propiedad será un array.
{
"data": {
// Tus datos de recurso aquí.
}
}
Otros miembros de nivel superior incluyen: errors
, meta
, links
e included
. De estos, included
será el más utilizado, pero se tratará más adelante en la documentación.
Para más información sobre la estructura de nivel superior, puedes consultar la especificación.
Dentro de los miembros data
e included
se encuentran los “objetos de recurso” (“resource objects”) u “objetos identificadores de recurso”. Los “objetos de recurso” representan el contenido de los recursos (entidades) con los que te preocuparás. Los “objetos identificadores de recurso” son como claves foráneas en una base de datos; identifican un recurso sin contener ninguno de sus campos. En términos de Drupal, un objeto de recurso es generalmente la representación JSON de una sola entidad, que puede ser un nodo, un término de taxonomía o un usuario. En términos de Drupal nuevamente, un identificador de recurso es solo la información necesaria para cargar una entidad: tienes su tipo y su ID, y nada más.
Todo objeto de recurso debe contener dos miembros: type
e id
. La única excepción es al crear una nueva entidad; en ese caso, el id
puede omitirse para permitir que Drupal genere un id para el nuevo recurso. Sin embargo, es completamente posible que la aplicación cliente proporcione un UUID para el recurso al crear una nueva entidad. Todos los ID en JSON:API son UUIDs.
El miembro type
es siempre obligatorio. El valor para type
se deriva del nombre del tipo de entidad y del bundle, si corresponde. El tipo para un recurso de entidad siempre sigue el patrón entity_type--bundle
. Por ejemplo, los tipos de nodo “article” y “basic page” del núcleo se representarán como: node--article
y node--page
.
Así, en una entidad sin propiedades ni campos obligatorios, se puede crear una nueva entidad con el siguiente JSON:
{
"data": {
"type": "node--my-bundle",
}
}
Sin embargo, esto no sería muy útil. Necesitamos incluir valores reales para la entidad. Para ello, JSON:API tiene dos miembros para almacenar valores: attributes
y relationships
. attributes
almacena valores específicos del recurso subyacente. relationships
son valores que pertenecen a otro recurso del sistema. En términos de Drupal, relationships
normalmente representa valores almacenados por una referencia de entidad. Por ejemplo, en el bundle article del núcleo, esto podría ser la propiedad uid
, ya que esta es una referencia de entidad al usuario que escribió el artículo. El cuerpo de un documento con attributes
y relationships
puede verse así:
{
"data": {
"type": "node--my-bundle",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"title": "Un Ejemplo"
},
"relationships": {
"uid": {
"data": {
"type": "user--user",
"id": "53bb14cc-544a-4cf2-88e8-e9cdd0b6948f"
}
}
}
}
}
Como puedes ver, la propiedad uid
vive bajo el miembro relationships
. Al igual que el recurso principal, también contiene un type
y un id
ya que es un recurso separado y distinto.
Nota que uid
no tiene attributes
ni relationships
. Esto es porque JSON:API no incluye el contenido de una relación a menos que se lo pidas específicamente mediante el uso de un parámetro de consulta especial, include
. Más sobre eso más adelante (ver "Obteniendo recursos (GET)").
Para más detalles sobre la estructura de los objetos de recurso, puedes consultar la especificación.
§ Identificadores de recurso "virtuales"
En algunas circunstancias, Drupal permite que una relación apunte a un recurso (una referencia de entidad a otra entidad) que no está almacenado en la base de datos y, por tanto, no es recuperable mediante JSON:API. El identificador de recurso “virtual” puede señalar diferentes circunstancias según su contexto, aunque siempre corresponderá a un recurso que no puede ser encontrado.
Uso y significado del identificador de recurso “virtual” en Drupal core
El campo parent
de término de taxonomía es el ejemplo más relevante de este caso especial en el core de Drupal. Este campo de relación puede contener un identificador de recurso para un término de taxonomía “virtual”. En este caso, el identificador “virtual” identifica el término raíz (<root>
) de la taxonomía. Esto indica que el término referenciado está en el nivel superior de su vocabulario.
Observa el siguiente documento de respuesta para un término de taxonomía hipotético:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Política"
},
"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": "Uso y significado del identificador de recurso 'virtual'."
}
}
}
}
}
]
}
}
}
}
Observa cómo la relación parent
(un campo de referencia de entidad) tiene un objeto identificador de recurso donde id
no es un UUID, sino "virtual"
. Esto es necesario porque un término de nivel superior o raíz tiene una referencia a un término <root>
no almacenado (target_id = 0
) como su padre.
¿Por qué?
Dado que el término raíz no está almacenado y un término puede tener más de un padre, la pregunta crucial es: ¿cómo distinguimos entre un término que:
- tiene solo el término
3
como su padre ([3]
)? - tiene tanto el término raíz no almacenado y el término
3
([0, 3]
)?
La respuesta es que si JSON:API omitiera el término raíz no almacenado 0
en vez de usar el id "virtual"
, ¡no sería posible distinguir entre estos dos casos!
§ Identificadores de recurso "missing" (faltantes)
Drupal no "limpia" las relaciones hacia recursos que han sido eliminados (campos de referencia de entidad que apuntan a entidades eliminadas). Es decir, Drupal deja en su lugar las relaciones “colgantes” (referencias a entidades inexistentes).
Cuando JSON:API encuentra este tipo de relaciones colgantes, usará el identificador de recurso “missing”.
Uso y significado del identificador de recurso “missing” en Drupal core
Siguiendo el ejemplo anterior del identificador 'virtual': el campo parent
de término de taxonomía. Imagina que cierto término de taxonomía tenía como padre el término “Bélgica”, pero ahora dicho término ya no existe —tal vez porque el pequeño país dejó de existir. Entonces este campo de relación contendría un identificador de recurso “missing”.
Observa el siguiente documento de respuesta para un término de taxonomía hipotético:
{
"data": {
"type": "taxonomy_term--tags",
"id": "2ee9f0ef-1b25-4bbe-a00f-8649c68b1f7e",
"attributes": {
"name": "Política"
},
"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": "Uso y significado del identificador de recurso 'missing'."
}
}
}
}
}
]
}
}
}
}
Observa cómo la relación parent
tiene un objeto identificador de recurso donde id
no es un UUID, sino "missing"
. Además, su type
es unknown
(porque Drupal no almacena el bundle de la entidad referenciada, solo el tipo de entidad; por lo tanto, determinar el nombre del tipo de recurso JSON:API es imposible).
Artículo de la Documentación de Drupal.