Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
As explained in Proposing an alternative to application/vnd.drupal.ld+json, the new plan is to use HAL as the primary format for REST. First we'll need to decide how to serialize an entity to hal+json.
We will definitely add a link for each entity reference. Some have stated a preference for additionally including the entity reference field with the other fields in the resource's state.
Proposed resolution
Add a set of Normalizers and an Encoder, creating the following JSON structure:
{
"_links": {
"self": {
"href": "http://d8.l/entity/entity_test/3"
},
"type": {
"href": "http://d8.l/rest/type/entity_test/entity_test"
},
"http://d8.l/rest/relation/entity_test/entity_test/field_test_entity_reference": [
{
"href": "http://d8.l/entity/entity_test/1",
"lang": "de"
},
{
"href": "http://d8.l/entity/entity_test/2",
"lang": "en"
}
]
},
"_embedded": {
"http://d8.l/rest/relation/entity_test/entity_test/field_test_entity_reference": [
{
"_links": {
"self": {
"href": "http://d8.l/entity/entity_test/1"
},
"type": {
"href": "http://d8.l/rest/type/entity_test/entity_test"
}
},
"uuid": [
{
"value": "083028f3-f851-4ba9-a763-996bc09e9338"
}
],
"lang": "de"
},
{
"_links": {
"self": {
"href": "http://d8.l/entity/entity_test/2"
},
"type": {
"href": "http://d8.l/rest/type/entity_test/entity_test"
}
},
"uuid": [
{
"value": "daf2fd6e-d9e3-4566-ac06-6fb2379cc374"
}
],
"lang": "en"
}
]
},
"uuid": [
{
"value": "c4d98886-533a-4270-8e00-b490a8c44580"
}
],
"langcode": [
{
"value": "de"
}
],
"name": [
{
"value": "uP7sBcAa",
"lang": "de"
},
{
"value": "rM0oP6vM",
"lang": "en"
}
],
"field_test_text": [
{
"value": "jUedNbKA",
"format": "full_html"
}
]
}
Comment | File | Size | Author |
---|---|---|---|
#19 | interdiff.txt | 2.63 KB | linclark |
#18 | 1924220-18-hal-serialize.patch | 31.71 KB | linclark |
#16 | 1924220-16-hal-serialize.patch | 31.63 KB | linclark |
#16 | interdiff.txt | 6.3 KB | linclark |
#15 | 1924220-15-hal-serialize.patch | 35.68 KB | linclark |
Comments
Comment #1
Anonymous (not verified) CreditAttribution: Anonymous commentedBased on the preference described in the issue summary, this patch creates the following structure. I'm not sure that we will want to include the entity references in the state, but for now it is, with UUID as its only property.
We also may want to consider defining relations in a Drupal namespace. For example, site:type could be drupal:type instead since that is a relation that will always mean the same thing across the different sites.
This patch depends on #1921490: $supportedInterfaceOrClass should not be static.
Comment #3
Crell CreditAttribution: Crell commentedJust quick notes for now:
Does UUID need to be a multi-value field? That seems odd.
What's curies?
Comment #4
Anonymous (not verified) CreditAttribution: Anonymous commentedWe could add special processing for UUID if we want to. However it would require a conditional check on the property name since there is no special Typed Data API datatype for UUID, and thus no class or interface to use to switch the Normalizer.
That refers to the CURIEs used in XML and RDF to shorten URIs by using prefixes... for example, site:user_id expands to http://example.com/relations/user_id. So the "curies" array provides namespace templates that can be used to expand the CURIE. The Web Linking RFC (rfc5988) recommends that link relations be URIs if you aren't going to register them with IANA. My understanding is that HAL does not require conformance with this RFC, but if you do use it then the HAL Browser is a more effective documentation tool. For example, checkout the browser for HAL Talk and click on the docs link next to a property like ht:users.
I realized after you asked that the /{rel} got dropped from the end of the 'href' in the curie object when I was editing the Normalizer, so I've added that back in. That's required for the templating to work.
Comment #5
Anonymous (not verified) CreditAttribution: Anonymous commentedThe test fail was based on the change from #1891516: Remove $install parameter from DrupalUnitTestBase::enableModules(), encourage individual schema tables. I was able to make it stop failing, but it still throws exceptions based on the use of
language()
in EntityNG and EntityBCDecorator.Comment #7
Anonymous (not verified) CreditAttribution: Anonymous commentedIt turns out that there is a "type" link relation in the IANA registry, so we wouldn't need to coin drupal:type.
Comment #7.0
Anonymous (not verified) CreditAttribution: Anonymous commentedAdded JSON.
Comment #8
Anonymous (not verified) CreditAttribution: Anonymous commentedThis patch:
I wanted to use _embedded for now because it is more expressive... it makes it clear that the UUID of the target entity is a property of that separate entity, not of the entity_reference field. We can change this later if need be, but I'd rather try it out this way.
I have added the JSON structure to the issue summary.
Comment #9
Anonymous (not verified) CreditAttribution: Anonymous commentedThe two big changes in this patch are:
EDIT: This also introduces a dependency on REST module. I felt that the hypermedia link relations should be independent of the format, which is why I put them in REST.
Comment #10
sunI'd love to help you further here, but unfortunately, I'm not familiar with this (entire) part of the code-base yet. I hope that @klausi and others can review this as soon as possible. This patch actually looks relatively simple.
Architecturally, I only have one concern, but it is off-topic for this issue:
The hal.module is empty. I'm really not sure whether it is a good idea to add these serializers as independent modules, if their entire functionality consists of cleanly decoupled classes only. By the looks of this code, I'd almost be tempted classify serializers as plugins...?
But as mentioned, that's off-topic for this issue. Merely had a brief look at the patch and this is what crossed my mind, so I wanted to mention it :)
Comment #10.0
sunremoved user_id
Comment #11
Anonymous (not verified) CreditAttribution: Anonymous commentedThanks for taking a look at the code :)
We don't need to make it a plugin in order to make it not it's own module. We could handle it the same way that the JSON and XML Normalizers and Encoders are handled, as part of serialization module. We don't add new Serializers, there is only one serializer which is registered with the container. In a compiler pass, the support for different formats is added to this Serializer using Normalizers and Encoders. The Serializer then uses a chain of command pattern to determine which Normalizers to use for a request.
So we don't need to have a module per format. However, in this patch I introduce a dependency on REST module. REST module has a dependency on Serialization module, so adding the HAL functionality to serialization module would create a circular dependency.
Comment #12
klausi@file doc block is missing that says that Drupal needs this empty file.
Should be "Contains ...", see http://drupal.org/node/1354#files
Why do we skip the id? Please add a comment.
is that needed?
What is this cache for? Should have a short description.
But that are just nitpicks, otherwise looks fine from a visual review.
Comment #13
Anonymous (not verified) CreditAttribution: Anonymous commentedFixed issues from Klaus's post and also fixed a bug when an empty entity is serialized.
Because we shouldn't expose internal IDs to the external world. Only UUID/URI are suitable identifiers for a hypermedia context.
Comment #14
Anonymous (not verified) CreditAttribution: Anonymous commentedUpdated for the change from .info to .info.yml.
Comment #14.0
Anonymous (not verified) CreditAttribution: Anonymous commentedUpdated the JSON representation.
Comment #14.1
Anonymous (not verified) CreditAttribution: Anonymous commentedUpdated the JSON.
Comment #15
Anonymous (not verified) CreditAttribution: Anonymous commentedThis patch adds a RelationLinkManager and changes all of the CURIEs and relative URIs to absolute URIs. We can change the link relations back to CURIEs later if we want to.
Comment #16
Anonymous (not verified) CreditAttribution: Anonymous commentedI removed the caching of type and relation links, since that won't be used until #1880424: Handle entity references on import.
Comment #17
klausinew line error
why do you have to check for EntityNG here? The uri method exists on the entity class already and works for me?
superfluous use statement
superfluous use statement.
I tested the module manually and it works as advertised. The test case also seems to cover the functionality sufficiently, so I would say this is RTBC.
Comment #18
Anonymous (not verified) CreditAttribution: Anonymous commentedThanks, I made all the changes except for the one below. I also added HAL module to MAINTAINERS.txt.
By new line error, I assume you mean the dash in front of 'serialization'. If you look at picture.info.yml, it also includes a second dash. I'd say we stick with it for now and go through and correct all of the info files if we're going to go with more standard YAML format.
Comment #19
Anonymous (not verified) CreditAttribution: Anonymous commentedAnd here's the interdiff I forgot...
Comment #20
webchickMy spidey sense is telling me this is the kind of thing Dries might want to sign off on.
Comment #21
Dries CreditAttribution: Dries commentedCommitted to 8.x. Thanks. Now let's remove JSON-LD from core.
Comment #22
Anonymous (not verified) CreditAttribution: Anonymous commentedThere is a patch to remove it. However, it depends on other things getting in, like HAL deserialization #1931976: Support deserialization for hal+json (needs more language handling tests) and converting REST module to use HAL for its tests #1935538: Switch REST to default to HAL.
Comment #23.0
(not verified) CreditAttribution: commentedRearranged _embedded
Comment #24
effulgentsia CreditAttribution: effulgentsia commentedThis patch introduced some
@todo Make the base path configurable.
comments, but with no issue link. I'm proposing to remove these comments in #2423951: Document each use of base: in rest.module. Please comment there if you disagree with that.Comment #25
effulgentsia CreditAttribution: effulgentsia at Acquia commented#2304849: Stop excluding local ID and revision fields from HAL output proposes to expose the internal ID. What were the reasons for not wanting it exposed? Please comment on that issue. Thanks.