Problem/Motivation
When using the hal_json
format with an entity that has a file
field the hal_json
output on GET
does not provide enough information to access the file
entity via the REST API.
I discovered this while reviewing #1927648: Allow creation of file entities from binary data via REST requests
I wanted to GET a node with a file field then be able to either GET, POST, PATCH or DELETE the file referenced. The example was working with had both a image and file field.
Here is the node GET response, the example has an image
field, a public://
file
field and a private://
file
field.
{
"_links": {
"self": {
"href": "http://d8.dev/node/37?_format=hal_json"
},
"type": {
"href": "http://d8.dev/rest/type/node/article"
},
"http://d8.dev/rest/relation/node/article/revision_uid": [
{
"href": "http://d8.dev/user/1?_format=hal_json"
}
],
"http://d8.dev/rest/relation/node/article/uid": [
{
"href": "http://d8.dev/user/1?_format=hal_json",
"lang": "en"
}
],
"http://d8.dev/rest/relation/node/article/field_image": [
{
"href": "http://d8.dev/sites/default/files/2017-09/webform1.png",
"lang": "en"
}
],
"http://d8.dev/rest/relation/node/article/field_private_file": [
{
"href": "http://d8.dev/system/files/2017-09/interdiff-109-115.txt"
}
],
"http://d8.dev/rest/relation/node/article/field_public_file": [
{
"href": "http://d8.dev/sites/default/files/2017-09/interdiff-275-277.txt"
}
],
"http://d8.dev/rest/relation/node/article/field_tags": [
{
"href": "http://d8.dev/taxonomy/term/1?_format=hal_json",
"lang": "en"
}
]
},
"nid": [
{
"value": 37
}
],
"uuid": [
{
"value": "aef1528d-aedb-4afc-a20a-755a71805937"
}
],
"vid": [
{
"value": 53
}
],
"langcode": [
{
"value": "en",
"lang": "en"
}
],
"type": [
{
"target_id": "article"
}
],
"revision_timestamp": [
{
"value": "2017-09-07T19:33:55+00:00",
"format": "Y-m-d\\TH:i:sP"
}
],
"_embedded": {
"http://d8.dev/rest/relation/node/article/revision_uid": [
{
"_links": {
"self": {
"href": "http://d8.dev/user/1?_format=hal_json"
},
"type": {
"href": "http://d8.dev/rest/type/user/user"
}
},
"uuid": [
{
"value": "3d76e74e-25b5-45e9-af89-3d94f253b46c"
}
]
}
],
"http://d8.dev/rest/relation/node/article/uid": [
{
"_links": {
"self": {
"href": "http://d8.dev/user/1?_format=hal_json"
},
"type": {
"href": "http://d8.dev/rest/type/user/user"
}
},
"uuid": [
{
"value": "3d76e74e-25b5-45e9-af89-3d94f253b46c"
}
],
"lang": "en"
}
],
"http://d8.dev/rest/relation/node/article/field_image": [
{
"_links": {
"self": {
"href": "http://d8.dev/sites/default/files/2017-09/webform1.png"
},
"type": {
"href": "http://d8.dev/rest/type/file/file"
}
},
"uuid": [
{
"value": "ce48df6b-83e9-47b8-9875-c2fe391ef9b1"
}
],
"uri": [
{
"value": "http://d8.dev/sites/default/files/2017-09/webform1.png"
}
],
"lang": "en"
}
],
"http://d8.dev/rest/relation/node/article/field_private_file": [
{
"_links": {
"self": {
"href": "http://d8.dev/system/files/2017-09/interdiff-109-115.txt"
},
"type": {
"href": "http://d8.dev/rest/type/file/file"
}
},
"uuid": [
{
"value": "50ab6ba6-7a86-4027-a86d-a26ebf0e09b5"
}
],
"uri": [
{
"value": "http://d8.dev/system/files/2017-09/interdiff-109-115.txt"
}
]
}
],
"http://d8.dev/rest/relation/node/article/field_public_file": [
{
"_links": {
"self": {
"href": "http://d8.dev/sites/default/files/2017-09/interdiff-275-277.txt"
},
"type": {
"href": "http://d8.dev/rest/type/file/file"
}
},
"uuid": [
{
"value": "bb9ed1d1-f613-4647-b932-2e2f52143bfd"
}
],
"uri": [
{
"value": "http://d8.dev/sites/default/files/2017-09/interdiff-275-277.txt"
}
]
}
],
"http://d8.dev/rest/relation/node/article/field_tags": [
{
"_links": {
"self": {
"href": "http://d8.dev/taxonomy/term/1?_format=hal_json"
},
"type": {
"href": "http://d8.dev/rest/type/taxonomy_term/tags"
}
},
"uuid": [
{
"value": "5228c13c-265a-42d1-bbca-ea4a30385cfc"
}
],
"lang": "en"
}
]
},
"status": [
{
"value": true,
"lang": "en"
}
],
"title": [
{
"value": "uuuuu",
"lang": "en"
}
],
"created": [
{
"value": "2017-09-06T14:22:27+00:00",
"lang": "en",
"format": "Y-m-d\\TH:i:sP"
}
],
"changed": [
{
"value": "2017-09-07T19:33:55+00:00",
"lang": "en",
"format": "Y-m-d\\TH:i:sP"
}
],
"promote": [
{
"value": true,
"lang": "en"
}
],
"sticky": [
{
"value": false,
"lang": "en"
}
],
"default_langcode": [
{
"value": true,
"lang": "en"
}
],
"revision_translation_affected": [
{
"value": true,
"lang": "en"
}
],
"path": [
{
"alias": null,
"pid": null,
"langcode": "en",
"lang": "en"
}
],
"content_translation_source": [
{
"value": "und",
"lang": "en"
}
],
"content_translation_outdated": [
{
"value": false,
"lang": "en"
}
],
"comment": [
{
"status": 2,
"cid": 0,
"last_comment_timestamp": 1504707773,
"last_comment_name": null,
"last_comment_uid": 1,
"comment_count": 0,
"lang": "en"
}
]
}
Nowhere in the response do I have access to the file
entity's id or url to access the file
entity via the REST API.
This not true for the other entity reference fields.
For the term I am given: "href": "http://d8.dev/taxonomy/term/1?_format=hal_json
and for the user I am given: "href": "http://d8.dev/taxonomy/term/1?_format=hal_json
Therefore I wanted to view, update or delete the file entity I would not be able to via REST.
Proposed resolution
Not sure but somehow return http://d8.dev/entity/file/1?_format=hal_json
Remaining tasks
User interface changes
API changes
Response for hal_json
normalized file fields would be changed.
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#17 | interdiff-14-16.txt | 1006 bytes | neel24 |
#16 | 2907402-16.patch | 6.71 KB | Berdir |
#14 | 2907402-14.patch | 6.67 KB | Berdir |
#13 | 3009854-38.patch | 18.62 KB | Berdir |
Comments
Comment #2
Wim LeersComment #3
Wim LeersThe root cause:
\Drupal\hal\Normalizer\FileEntityNormalizer::normalize()
:Assigning to @damiankloip for feedback.
Comment #4
Wim LeersQuoting #1927648-426: Allow creation of file entities from binary data via REST requests:
Comment #5
Wim LeersSee #2825487-141: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field:
Comment #6
damiankloip CreditAttribution: damiankloip at Acquia commentedHmm, I think with #2825487: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field we will get something like this with the new behaviour:
So, I think we will still have no way to get the file resource url (
entity/file/1?_format=hal_json
). However, the file entity also doesn't have any link templates to actually construct this? '_links.self.href' will still return the url created byfile_create_url()
, as it calls$file->url()
from\Drupal\hal\Normalizer\ContentEntityNormalizer::getEntityUri(
).It seems like it would be more correct to return what you suggest, not sure we can due to BC concerns though?
Comment #7
Wim LeersIndeed :(
But so then how do we evolve this from "it doesn't make sense right now but we can't change it due to BC" to a place where it does make sense, gradually, without breaking BC?
It seems impossible?
Oh heh, I'm basically again arriving at the same conclusion I already posted in #5/#2825487-141: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field:
Do you agree? That'd mean this is
Closed (works as designed)
and #2825487: Fix normalization of File entities: file entities should expose the file URL as a computed property on the 'uri' base field would fix it for new sites, but wouldn't fix it for existing sites.Comment #8
damiankloip CreditAttribution: damiankloip at Acquia commentedHmm, I was thinking in #6 that [#12357069] doesn't actually fix it for any sites. Yes, it would give them the uri field value and (new) url property, but I think @tedbow is getting at the fact that he is wanting to find something like /entity/file/1 - to be able to arrive at the file entity endpoint from a link here.
This might well not be fixable. To me (from #6 too) is the crux of the problem:
Hal generically gets links to the entity resource, but because file entity is 'special' that yields the path to the file the file entity represents, not the entity itself.
Comment #12
Wim LeersSee #3009854-25: Fix "The "serializer.normalizer.file_entity.hal" normalizer service is deprecated: it is obsolete, it only remains available for backwards compatibility." deprecation error + #3009854-26: Fix "The "serializer.normalizer.file_entity.hal" normalizer service is deprecated: it is obsolete, it only remains available for backwards compatibility." deprecation error.
Comment #13
BerdirActually, I decided to re-open this after talking with @alexpott. Posting the patch from the other issue here. Not sure yet if we'll only do the addition here, in which case we wouldn't need any setting or so. And then deal with files entirely in #2925520: Add a computed 'file_url' property to FileItem (for exposing file URL in file field normalization)
Comment #14
BerdirOk, this is now solely a backwards-compatible addition/bugfix (empty self.href definition), all file stuff removed. Might still get into 8.8 then?
Could still do a change record I suppose.
Comment #15
Wim LeersI first found #3009854-39: Fix "The "serializer.normalizer.file_entity.hal" normalizer service is deprecated: it is obsolete, it only remains available for backwards compatibility." deprecation error and was very confused. I wondered:
… but #14 does exactly that; it adds that
_links.self
URI 🙂I think this is a sensible improvement.
Comment #16
BerdirRerolled, not sure why this wasn't set back to needs work.
Comment #17
neel24 CreditAttribution: neel24 at Google Code-In commentedAttaching interdiff for patch in #14 and #16.
Comment #18
Wim LeersComment #20
BerdirRandom fail in ckeditor tests.
Comment #22
BerdirAgain a random fail, in 1) Drupal\Tests\taxonomy\Functional\TermAutocompleteTest::testAutocompleteOrderedResults, see https://www.drupal.org/pift-ci-job/1531654.
Comment #27
catchCommitted/pushed to 9.0.x and cherry-picked back to 8.9.x, I think parity between 9.x and 8.9 makes this a good backport candidate. Thanks everyone!
Comment #28
Wim Leers🥳