Problem/Motivation
At present serialization of entities with their references requires the link managers in rest module.
This means modules like hal and default_content rely on having rest module enabled, when all they really want to do is deserialize/denormalize entities with references intact.
We shouldn't need rest module enabled to be able to normalize/denormalize to and from hal_json or any other format that supports entity reference relations.
Proposed resolution
Move the following services/classes into serialization module.
rest.link_manager:
class: Drupal\rest\LinkManager\LinkManager
arguments: ['@rest.link_manager.type', '@rest.link_manager.relation']
rest.link_manager.type:
class: Drupal\rest\LinkManager\TypeLinkManager
arguments: ['@cache.default', '@module_handler', '@config.factory', '@request_stack']
rest.link_manager.relation:
class: Drupal\rest\LinkManager\RelationLinkManager
arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']
Leave the old classes behind, make them empty shells that extend from the ones in serialization and mark them as deprecated.
Make hal module use the serialization module version.
Make hal module no longer depend on rest module.
Write tests to verify the above is true.
Remaining tasks
Agree if this is something we want to do
Patch
User interface changes
None
API changes
None
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#51 | increment.txt | 482 bytes | effulgentsia |
#51 | 2758897-51.patch | 69.94 KB | effulgentsia |
#49 | increment.txt | 790 bytes | effulgentsia |
#49 | 2758897-48.patch | 70.04 KB | effulgentsia |
#43 | interdiff-2758897-43.txt | 913 bytes | damiankloip |
Comments
Comment #2
larowlanComment #3
dawehner+1 for the general idea.
There was also an issue to also get rid of serialization module and move it to core instead. Serialization module was initially just there, because core was less flexible in some place.
Comment #4
Wim Leers+1 for concept.
Also +1.
Comment #6
larowlanComment #7
Wim LeersIs this possible to do without breaking BC?
Comment #8
larowlanYep, we have to leave the old services/classes behind extending from the parent.
We did similar for BrowserTestBase, left a deprecated shell behind in simpletest module but moved the actual guts to core's Tests namespace
Comment #9
Wim LeersOk. If you can provide a patch, I'd be happy to review it.
However, how is this going to interact with #2296029: Move Serialization module back into a core/lib component? Does that mean we just move this service directly into core? In other words, this could then be a precursor for #2296029: Move Serialization module back into a core/lib component, and a much smaller one at that! :)
Comment #10
Grayside CreditAttribution: Grayside at Phase2 commentedAnother consideration is the interaction between serialization and HTTP headers. E.g., suppose URLs derived by the existing Link managers should be used in Link headers? Should that be supported without requiring event subscribers to decode the serialized result?
This is related to the general class of behaviors that might change HTTP headers or cache tags based on processing objects.
Comment #11
Wim LeersThis blocks #2473749: Remove rest as a dependency of hal.
Comment #12
e0ipso+1 on this.
Comment #13
Wim LeersAlright, let's get this going. Here's an initial patch.
Still TODO:
link_domain
setting fromrest.settings
toserialization.settings
. This is an upgrade path. And it will need tests. (See\Drupal\serialization\LinkManager\LinkManagerBase::getLinkDomain()
.)\Drupal\serialization\LinkManager\RelationLinkManager::getRelationUri()
\Drupal\serialization\LinkManager\TypeLinkManager::getTypeUri()
But before spending time on that, I wanted a +1 on this approach so far.
Comment #14
Wim LeersThis blocks #2829746: Clean up \Drupal\jsonapi\LinkManager\LinkManager(Interface), which is currently contrib, but we're working on moving the JSON API module into core (see #2757967: API-first initiative). So tagging .
Comment #15
larowlanOh man, I totally worked on this during a plane ride from QLD to NSW, but forgot to upload it.
Good thing is we have essentially the same code.
In terms of 2 and 3 I'd replace 'REST' module with 'Drupal'
Thanks Wim, looking good.
Comment #16
e0ipsoThis also looks good to me. Thanks Wim!
Comment #17
Wim Leers#15 + #16: thanks for the swift reviews! :)
#15: Oh :( Well, great to see both of our work validated then :) Thanks for the suggestion for points 2 + 3.
This addresses #13.2 and #13.3. It also ensures BC for
hook_rest_(type|relation)_uri_alter()
.Comment #18
Wim LeersUgh. I only added a new file in #17. Here's the rest of the intended changes.
Comment #19
Wim LeersIn #18, I also updated the default type/relation URIs from
$this->getLinkDomain() . "/rest/…"
to$this->getLinkDomain() . "/serialization/…"
. This breaks BC. So, reverting that change.(#18 should also fail, because
RestLinkManagerTest
will catch this change. #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method would also detect this BC break. We really need #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method to land.)Comment #20
Wim LeersSo #18 made it so that the invocation of
hook_rest_(type|relation)_uri_alter()
hooks happens in the link manager classes that have been moved to theserialization
module. In other words:these hooks are now renamed to
hook_serialization_(type|relation)_uri_alter()
but the old hooks are also still called, to ensure BC
What I had not yet done, was updating
\Drupal\Tests\rest\Kernel\RestLinkManagerTest
. It uses therest_test
module, which contains therest_test_rest_type_uri_alter()
andrest_test_rest_relation_uri_alter()
hook implementations. Those should be moved to theserialization_test
module. And the implementations in therest_test
module should be kept to test BC.Comment #21
Wim LeersSome context for the changes in #20.
Note this is no longer installing the
rest
module. No more dependence onrest
, yay!Note that we still have
rest_test
there, but solely for testing BC of those alter hooks.The last two lines used to be originally in the place of those first two lines. Now the primary test must of course be the
hook_serialization_*
alter hooks. So we test that first, and then assert that BC works.Comment #23
Wim LeersAaand upgrade path plus tests. There is explicit test coverage for both possible cases:
serialization
module is installed,rest
module is NOT installed: test coverage ensuresserialization.settings
is created and containslink_domain: ~
.serialization
andrest
modules are both installed: test coverage ensuresserialization.settings
is created, with alink_domain
value that is migrated fromrest.settings
, andlink_domain
is deleted fromrest.settings
Comment #25
Wim Leersgit + binary patches (or files with serialized PHP, which are strings, which git insists on interpreting as binary) == pain
Identical patch, but this time with
--binary
.Comment #26
Wim LeersYay! The upgrade path tests passed :)
This is now ready for final review. Just reading the interdiffs since #13 is sufficient!
Comment #27
larowlanIs rest.settings the correct example?
should we use
serialize(8000)
here so its explicit what the format is? Depends what we do elsewhere I guess.Do we normally reference issues like this?
Comment #28
Wim LeersRE:
rest.settings
: HAH! Great catch :) Fixed.\Drupal\rest\Tests\Update\EntityResourcePermissionsUpdateTest
and\Drupal\rest\Tests\Update\ResourceGranularityUpdateTest
.Comment #29
Wim LeersChange record created: https://www.drupal.org/node/2830467.
Comment #30
Wim LeersFrom the IS:
This is what #28 does.
We don't do this yet! So, doing that now.
Perhaps this belongs in a separate issue. But I'll leave that up to the committer to decide. If we want to do it separately, we'll just need to revert this interdiff :)
Comment #32
Wim LeersHm…
It seems this is failing because of:
i.e. the
serialization
module does not depend on therest
module, so it seems it's possible that the using of the old interface to guarantee BC doesn't actually work. Presumably the autoloader doesn't allow REST module's classes to be accessed when the REST module is not installed.It just happens to be that #30 exposes that flaw.
Is that theory correct? If so, I don't know what the best way to fix this would be, without breaking BC. IOW, what @larowlan proposed in #8 would appear to be impossible:
Moving things to
lib/Drupal/Core
is possible, because that's guaranteed to be always present. In the case of this issue/patch, we're moving it to therest
module, which is not guaranteed to be present.So, do we want to move the link manager to
lib/Drupal/Core
instead (like I already proposed in #9)? That'd partially solve #2296029: Move Serialization module back into a core/lib component too. But then what about thelink_domain
setting? That could then no longer live inserialization.settings
.Moving to NR for feedback.
Comment #33
larowlanin my head it worked the other way around, the rest ones extended from serialization, looking at my patch that was the approach I was taking too.
Comment #34
damiankloip CreditAttribution: damiankloip at Acquia commentedHere is a reroll to start with. Plus interdiff with the main significant change conflict.
Comment #36
damiankloip CreditAttribution: damiankloip at Acquia commentedLet's try again.
Comment #37
damiankloip CreditAttribution: damiankloip at Acquia commentedWhoops.
Comment #38
damiankloip CreditAttribution: damiankloip at Acquia commentedSo, can we do this instead? Agree we cannot have rest classes/interfaces being depended on in serialization module. This seems like the only real solution?
Comment #39
damiankloip CreditAttribution: damiankloip at Acquia commentedYes, I failed at copying these comments properly.
Comment #42
Wim Leers#38 passes. #30 fails. So clearly @damiankloip's approach is feasible (#38), mine is not (#30).
#38 summarizes his approach like this:
Effectively, this means:
LinkManager
was moved fromrest
toserialization
, but it continued to implement theLinkManagerInterface
fromrest
.This did not work for the reasons given in #32.
Same for the
RelationLinkManager
andTypeLinkManager
classes.Consequently, the thin
LinkManager
class that was created inrest
just to avoid breaking code is now itself responsible for implementing the corresponding original interface (the one inrest
). That's what's being changed here.And as a final consequence, the
rest.link_manager
service can no longer point to theserialization.link_manager
service, because it must continue to implement the interface defined in therest
module to not break BC. So it must not be an alias to another service, but instead it must point to the class highlighted in the previous point.AFAICT this is solid. RTBC.
Thanks, @damiankloip!
Just marking NW instead of RTBC for the nits that @damiankloip already pointed out himself in #39, then this is RTBC.
Comment #43
damiankloip CreditAttribution: damiankloip at Acquia commentedThanks, Wim! Thanks for the comprehensive write up. That seems 100% accurate :) We keep the REST services (as they extend the serialization ones now, but change the class only), and implement the original interfaces in the original classes only.
Comment #44
Wim LeersWhew! So glad to see this being ready :)
Also, bumping this to major, since it living in the
rest
module causes other modules to have to reimplement this. Without this being fixed, certain contrib modules can't move forward (see original report by @larowlan, plus the JSON API module, which has had to introduce its own link manager).Comment #46
Wim LeersHEAD broke due to a broken Outside-In commit. This is still RTBC.
Comment #48
effulgentsia CreditAttribution: effulgentsia at Acquia commentedComment #49
effulgentsia CreditAttribution: effulgentsia at Acquia commentedThis is the only @todo in this patch, and the upgrade path is already in the patch, so we should fix which config file we get this from, especially since the issue summary is about not requiring rest.module to be enabled. This patch does that.
Comment #50
effulgentsia CreditAttribution: effulgentsia at Acquia commentedTicking credit boxes.
Comment #51
effulgentsia CreditAttribution: effulgentsia at Acquia commentedRemoved unused use statements.
Comment #54
effulgentsia CreditAttribution: effulgentsia at Acquia commentedPushed to 8.4.x and cherry picked to 8.3.x.
Normally, the change in #49 would be something I would want another person to review, but because we're only a few hours from the alpha1 code freeze, I took the liberty of committing #51 without that review. I hope it's ok.
However, related to that change:
A follow-up issue to improve this test to not enable rest.module (implicitly via rest_test) would be great.
Comment #55
Wim LeersOops, #49 was indeed an oversight. Thanks!
Done, includes RTBC patch: #2848933: SerializationLinkManagerTest should not enable the rest_test module (because it implicitly enables the rest module).
Comment #56
Wim LeersComment #57
Wim LeersAnd hah, we apparently already fixed #2473749: Remove rest as a dependency of hal as part of this patch! :)
Comment #58
BerdirThis broke tests in entity_reference_revisions and possibly other modules as well.
https://www.drupal.org/pift-ci-job/589215
Was confused for a moment because the service still exists, but we were relying on the fact that hal depends on rest.module and didn't explicitly enable that in the test. The runtime code also only implicitly checks for rest, FileEntityServiceProvider (ERR has the same check without the comment):
Not sure if changing module dependencies is an API change or not? :)
Comment #59
Wim LeersGlad to hear it's just that :)
The
hal
module depending onrest
was always a flaw, as #2473749: Remove rest as a dependency of hal explained. Never rely on implicit module dependencies. Fortunately, it's an easy fix on your end — and for anybody else who may be using this :)Added this to the CR. And also published the CR — apparently @effulgentsia forgot to publish it :)
Comment #61
Wim LeersCritical follow-up for this issue: #2854830: Move rest/serialization module's "link manager" services to HAL module.