We have recently been seeing an issue related to field aliases, but we can't track down the root cause of it.
In a previous deployment we created a new date field (field_event_date_timezone) and then migrated dates from the existing field (field_event_date) to the new field. Using the json api alias config, we disabled field_event_date, and then set an alias for field_event_date_timezone to the old field name of "field_event_date". Maybe a picture will help explain:
We recently started seeing an issue when sorting on the field alias. When we hit the API and try to sort by doing the following:
sort=-field_event_date.value
An exception is thrown:
Drupal\Core\Http\Exception\CacheableBadRequestHttpException: Invalid nested filtering. The field `field_event_date`, given in the path `field_event_date.value`, does not exist. in Drupal\jsonapi\Context\FieldResolver->resolveInternalEntityQueryPath() (line 296 of /.../docroot/core/modules/jsonapi/src/Context/FieldResolver.php)
However, the big issue for us is that it isn't consistent. The issue crept up this morning and I consistently saw it when hitting the API directly from my browser. I decided to clear the Drupal cache, and now I no longer see it in my browser, but I occasionally see it in the logs. The inconsistency is what is making this hard to track down. I am not able to reproduce in any of our lower environments either.
Any thoughts on what could be happening?
Comment | File | Size | Author |
---|---|---|---|
#12 | 3143378-12.patch | 5.03 KB | bbrala |
| |||
2020-05-27_17-27-47.png | 5.48 KB | neuquen |
Comments
Comment #2
neuquen CreditAttribution: neuquen commentedComment #3
neuquen CreditAttribution: neuquen commentedI still can't reproduce the issue locally, but I decided to mimic the failure by sorting by a non-existent field.
My guess, after looking through the code, is that somehow the ResourceType/ConfigurableResourceType object is missing the field.
The stack trace shows that a jsonapi_extras ConfigurableResourceType is passed into the first argument of the resolveInternalEntityQueryPath() function.
Drupal\jsonapi\Context\FieldResolver->ResolveInternalEntityQueryPath() calls isMemberFilterable() which calls RsourceType::isFieldEnabled() which calls Resourcetype::hasField() which checks the ResourceType object to see if the key exists within the list of fields from the ConfigurableResourceType object:
Clearing the Drupal cache consistently fixes the problem, so caching the incorrect ResourceType/ConfigurableResourceType could be the issue. I've noticed specific $cacheability values being used, so it's obvious why it is being cached, but I'm not sure why it is being cached without that particular field.
I'm also not quite sure how jsonapi_extras actually sends the object to resolveInternalIntityQueryPath(). I noticed that
resolveInternalEntityQueryPath() receives the ResourceType object from Drupal\jsonapi\Controller\EntityResource->getCollectionQuery() which receives it from Drupal\jsonapi\Controller\EntityResource->getCollection(). But I'm not sure how jsonapi_extras passes the ResourceType to getCollection().
I poked around Drupal\jsonapi_extras\Entity\JsonapiResourceconfig.php and stepped through getFieldMapping(), which seemed to work fine.
Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType->overridFieldMapping() also successfully replaced the overridden field mappings.
It looks like Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository->createResourceType() actually creates the ConfigurableResourceType object to mimic the ResourceType object from the jsonapi module, and that includes $this->overrideFieldMapping(), so that looks like it should work as well.
At this point, I'm not sure if I'm even close, or if I've gone down the wrong path in the rabbit hole. Any help/guidance would be greatly appreciated.
Comment #4
neuquen CreditAttribution: neuquen commentedComment #5
neuquen CreditAttribution: neuquen commentedI think I'm stuck at this point.
I've been looking more closely at ConfigurableResourceType::overrideFieldMapping():
I'm noticing that it uses the Entity Type Manager to get the entity type definition, and then calls ResourceTypeRepository::getAllFieldNames() which uses the Entity Type Manager to get the field definitions, and return the array keys (field names) back to the overrideFieldMapping() function. I'm assuming that the Entity Type Manager isn't broken, so I would expect overrideFieldMapping() to always return the correct fields. JsonapiResourceConfig::getFieldMapping() also behaved fine when I tested it locally.
My biggest hang up at this point is that I can only mimic the invalid nested filtering error by intentionally passing in a non-existent field. I haven't been able to reproduce the error where an existing field is throwing the non-existent error message. With caching in the mix, I'm at a loss for how to replicate it.
Comment #6
neuquen CreditAttribution: neuquen commentedComment #7
e0ipsoI have had the opportunity to scan the issue you posted. It is very well described and reasoned. I wish all the bug reports were as thorough as that one!
I have never used the field aliasing as a way to deprecate a field and have other step in. That is clever. However I can see how that could lead to issues, if the presence of a field definition shortcuts the check for aliases.
Sadly I am not dedicating much of my spare time to maintenance these days. But if you find a fix for this and submit a patch with a test I'll be sure to merge it. In parallel I am also trying to find the best person to be the co-maintainer of this module.
Comment #8
bbralaHmm, when i read this issue i think this might be fixed with the changes made for 9.x compatibilty. The reference to the fields will probably change to the internal name and use the ResourceTypeField class to change public name. This would mean there is no unfortunate random overwriting of the field at the wrong time since the index in the array should be the internal name at all times.
https://www.drupal.org/project/jsonapi_extras/issues/3069220#comment-137...
Comment #9
bbralaComment #10
bbralaUnfortunately i reproduced this issue.
Comment #11
bbralaI tried to prove this problem in a test, but when sorting on a nested value i get the expected results.
Comment #12
bbralaRemoved a local change i added to speed things up.
Comment #14
bbralaComment #15
bbralaComment #16
bbrala