After updating jsonapi to 8x-1.21, the basepath overwrite from jsonapi_extras no longer works. It seems that jsonapi switched from getPathPrefix() to getBasePath().

Attached a patch file for the change.

Comments

ncvrk created an issue. See original summary.

wim leers’s picture

This is why @gabesullice and I hadn't tagged a new JSON API release yet, but @e0ipso tagged that 3 days ago: https://www.drupal.org/project/jsonapi/releases/8.x-1.21.

That's due to the changes committed in #2949632: Make ResourceTypeRepository aware of the path prefix, which were necessary to unblock #2971745: Don't hardcode `/jsonapi/` in FormatSetter, read JSON API base path from container parameter instead. But sadly, the approach in #2971745 causes a performance problem.

The root cause of that performance problem is the original commit in #2949632. If it had used a container parameter, that would not have been a problem. See #2971745-15: Don't hardcode `/jsonapi/` in FormatSetter, read JSON API base path from container parameter instead for an explanation (and the preceding comment for profiling numbers).

I'll work on a jsonapi_extras patch that makes it compatible with the jsonapi patch at #2971745-15.

ncvrk’s picture

Thanks @Wim Leers, I just looked into it a bit when I noticed my overwritten APIs stopped working after a composer update and threw that patch in the issue overview in case someone else ran into the same thing in the interim on 1.21 jsonapi before an official jsonapi_extras patch.

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Active » Needs review
StatusFileSize
new5.69 KB
wim leers’s picture

+++ b/src/EventSubscriber/ConfigSubscriber.php
@@ -0,0 +1,98 @@
+    $response->getCacheableMetadata()
+      ->addCacheTags(['config:jsonapi_extras.settings']);
...
+    // Run before \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::onResponse()
+    // (priority 128), so we can add JSON API's config cache tag.
+    $events[KernelEvents::RESPONSE][] = ['onResponse', 150];

+++ b/src/Normalizer/EntityNormalizerTrait.php
@@ -81,9 +81,6 @@ trait EntityNormalizerTrait {
-    $context['cacheable_metadata']->addCacheableDependency(
-      \Drupal::config('jsonapi_extras.settings')
-    );

These changes are for #2948666: Remove JSON API's use of $context['cacheable_metadata'], which landed today.

wim leers’s picture

+++ b/src/EventSubscriber/ConfigSubscriber.php
@@ -0,0 +1,98 @@
+  public function onSave(ConfigCrudEvent $event) {
+    if ($event->getConfig()->getName() === 'jsonapi_extras.settings') {
+      // @see \Drupal\jsonapi_extras\JsonapiExtrasServiceProvider::alter()
+      if ($event->isChanged('path_prefix')) {
+        $this->drupalKernel->rebuildContainer();
+        $container = \Drupal::getContainer();
+        // Because \Drupal\jsonapi\Routing\Routes::routes() uses a container
+        // parameter, we need to ensure that it uses the freshly rebuilt
+        // container. Due to that, it's impossible to use an injected route
+        // builder service, at least until core updates it to support
+        // \Drupal\Core\DrupalKernelInterface::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED
+        $this->service = $container->get('router.builder');
+        $container->get('router.builder')->rebuild();
+      }
+    }
+  }

+++ b/src/JsonapiExtrasServiceProvider.php
@@ -26,6 +27,10 @@ class JsonapiExtrasServiceProvider extends ServiceProviderBase {
+    $settings = BootstrapConfigStorageFactory::get()
+      ->read('jsonapi_extras.settings');
+    $container->setParameter('jsonapi.base_path', '/' . $settings['path_prefix']);

These changes are for #2971745-15: Don't hardcode `/jsonapi/` in FormatSetter, read JSON API base path from container parameter instead, which is the proposed patch for jsonapi, which does NOT suffer from performance problems.

wim leers’s picture

Status: Needs review » Needs work

The last submitted patch, 4: 2982133-3.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new5.67 KB

git shenanigans… functionally identical to the previous patch.

Status: Needs review » Needs work

The last submitted patch, 9: 2982133-9.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new393 bytes

Actually, it seems jsonapi_extras HEAD is broken in multiple ways. Let's see where things fail in HEAD by uploading a patch that just modifies the *.info.yml file.

Status: Needs review » Needs work

The last submitted patch, 11: 2982133-11-trigger_HEAD_test.patch, failed testing. View results

e0ipso’s picture

This is a brilliant patch, as usual! Thanks @Wim Leers.

  1. +++ b/src/EventSubscriber/ConfigSubscriber.php
    @@ -0,0 +1,98 @@
    +class ConfigSubscriber implements EventSubscriberInterface {
    ...
    +    $events[ConfigEvents::SAVE][] = ['onSave'];
    +    // Run before \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::onResponse()
    +    // (priority 128), so we can add JSON API's config cache tag.
    +    $events[KernelEvents::RESPONSE][] = ['onResponse', 150];
    +    return $events;
    

    It feels that the subscriber got more responsibilities after it got its name.

  2. +++ b/src/JsonapiExtrasServiceProvider.php
    @@ -26,6 +27,10 @@ class JsonapiExtrasServiceProvider extends ServiceProviderBase {
    +    $container->setParameter('jsonapi.base_path', '/' . $settings['path_prefix']);
    

    Maybe we should break off to JSON API Extras 3.x and:

    1. Change the config property to base_path to stay consistent with JSON API.
    2. Include the leading / in the configuration property (and validate that fact) to stay consistent with JSON API.

wim leers’s picture

  1. It feels that the subscriber got more responsibilities after it got its name.

    Hahahahahaha 😅😊 Is it that obvious? :D

    Happy to rename. Any suggestions?

    OTOH, it is all about JSON API Extras config!

  2. +1, but there's no reason we can't make it work today in 2.x, and then provide an upgrade path to 3.x!
wim leers’s picture

Assigned: Unassigned » wim leers

I'll try to drive this to the finish line.

wim leers’s picture

Something seriously weird is going on with static caching in ConfigurableResourceTypeRepository. I've been debugging it for over an hour.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new8.34 KB
new3.65 KB

I've figured out the weirdness in practice; everything works splendidly now in JSON API Extras: I can make a change in the configuration, and it instantly shows up. What is not working great though, is the test. That still fails in the same way. It must be due to some weird static caching bug in the test coverage…

Status: Needs review » Needs work

The last submitted patch, 17: 2982133-17.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

wim leers’s picture

Assigned: wim leers » Unassigned

I just finished literally stepping through the entirety of the route building process, for every stage of \Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest::testRead().

Because I can't figure out why $output = Json::decode($this->drupalGet('/api/articles')); is NULL.

Turns out it's because of a fatal error:

<b>Fatal error</b>:  Trait 'Shaper\DataAdaptor\DataAdaptorValidatorTrait' not found in <b>/Users/wim.leers/Work/d8/modules/jsonapi_extras/src/Plugin/ResourceFieldEnhancerBase.php</b> on line <b>25</b><br />"

GAAAAHHHHHHHH!!!!!!!!!!!!

So I wasted ~3 hours on this because BrowserTestBase::drupalGet() is braindead wrt error handling plus jsonapi_extras is not verifying that its dependencies are installed (even though it's irrelevant to this test coverage…).

When I install that locally, all tests pass:

Testing Drupal\Tests\jsonapi_extras\Functional\JsonExtrasApiFunctionalTest
.                                                                   1 / 1 (100%)

Time: 9.88 seconds, Memory: 6.00MB

OK (1 test, 15 assertions)

(Both on Drupal 8.5 & 8.6.)

wim leers’s picture

My only remaining suspicion is that it fails against PHP 7.1 due to #2971040: PHP 7.1 Compatibility Warning. So queued a test against PHP 5.5.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new8.73 KB
new415 bytes

I can try blaming local failures on infrastructure (although I probably shouldn't!), but I can't blame the patch here not passing tests. Because as DrupalCI's output shows:

00:01:08.001   - Installing drupal/jsonapi (1.21.0): Cloning 8.x-1.21

… that of course does not yet include #2971745: Don't hardcode `/jsonapi/` in FormatSetter, read JSON API base path from container parameter instead, which was committed only minutes ago, by yours truly. 😅

So, let's make it use the latest version of jsonapi that includes that commit. I think this should do it. (But this should definitely not get committed.)

wim leers’s picture

🚀🎉

Once a new jsonapi release is tagged, we can update the minimum version requirement in composer.json and jsonapi_extras.info.yml (which oddly don't match), and then we'll be good to go! 🤘

gabesullice’s picture

Status: Needs review » Needs work
Issue tags: +API-First Initiative

The final 1.x release of JSON API just landed, which includes the required comment. We can update Extras to require >= 1.22 then.

wim leers’s picture

Title: Base Path overwrite no longer works with jsonapi version 1.21 » No longer works with JSON API >=1.21 (so either 1.21 or 1.22)
wim leers’s picture

  • e0ipso committed 41b88c4 on 8.x-2.x authored by Wim Leers
    Issue #2982133 by Wim Leers, ncvrk, e0ipso, gabesullice: No longer works...
e0ipso’s picture

Status: Needs work » Fixed

Thanks for the fix! I changed the version to 1.22 on the commit.

wim leers’s picture

Status: Fixed » Reviewed & tested by the community

I changed the version to 1.22 on the commit.

👍

Although I wonder if jsonapi_extras.info.yml shouldn't also be updated? Moving back to RTBC for this.

e0ipso’s picture

@Wim Leers given that JSON API Extras relies on composer libraries, and therefore requires that installation method. Do you think #28 is still relevant?

e0ipso’s picture

Status: Reviewed & tested by the community » Active

I'm reopening this because this seems to have broken Contenta CMS's intaller:

 ~/Sites/contenta_docker   master  docker exec contenta_docker_php_1 init-drupal

Generating RSA private key, 2048 bit long modulus
.................................................................................+++
........................+++
e is 65537 (0x10001)
writing RSA key
You are about to DROP all tables in your 'contenta' database. Do you want to continue? (y/n): y
Starting Drupal installation. This takes a while. Consider using the        [ok]
--notify global option.
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException:    [error]
You have requested a non-existent service
"jsonapi.resource_type.repository". in
/var/www/vendor/symfony/dependency-injection/ContainerBuilder.php:1022
Stack trace:
#0
/var/www/vendor/symfony/dependency-injection/ContainerBuilder.php(589):
Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition('jsonapi.resourc...')
#1
/var/www/vendor/symfony/dependency-injection/ContainerBuilder.php(567):
Symfony\Component\DependencyInjection\ContainerBuilder->doGet('jsonapi.resourc...',
1)
#2 /var/www/web/core/lib/Drupal.php(159):
Symfony\Component\DependencyInjection\ContainerBuilder->get('jsonapi.resourc...')
#3
/var/www/web/modules/contrib/jsonapi_extras/src/Entity/JsonapiResourceConfig.php(116):
Drupal::service('jsonapi.resourc...')
#4
/var/www/web/modules/contrib/jsonapi_extras/src/Entity/JsonapiResourceConfig.php(76):
Drupal\jsonapi_extras\Entity\JsonapiResourceConfig::rebuildRoutes()
#5
/var/www/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(469):
Drupal\jsonapi_extras\Entity\JsonapiResourceConfig->postSave(Object(Drupal\Core\Config\Entity\ConfigEntityStorage),
false)
#6
/var/www/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(395):
Drupal\Core\Entity\EntityStorageBase->doPostSave(Object(Drupal\jsonapi_extras\Entity\JsonapiResourceConfig),
false)
#7
/var/www/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php(259):
Drupal\Core\Entity\EntityStorageBase->save(Object(Drupal\jsonapi_extras\Entity\JsonapiResourceConfig))
#8 /var/www/web/core/lib/Drupal/Core/Entity/Entity.php(391):
Drupal\Core\Config\Entity\ConfigEntityStorage->save(Object(Drupal\jsonapi_extras\Entity\JsonapiResourceConfig))
#9
/var/www/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php(637):
Drupal\Core\Entity\Entity->save()
#10
/var/www/web/core/lib/Drupal/Core/Config/ConfigInstaller.php(330):
Drupal\Core\Config\Entity\ConfigEntityBase->save()
#11
/var/www/web/core/lib/Drupal/Core/Config/ConfigInstaller.php(134):
Drupal\Core\Config\ConfigInstaller->createConfiguration('', Array)
#12
/var/www/web/core/lib/Drupal/Core/ProxyClass/Config/ConfigInstaller.php(75):
Drupal\Core\Config\ConfigInstaller->installDefaultConfig('module',
'recipes_magazin...')
#13
/var/www/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php(263):
Drupal\Core\ProxyClass\Config\ConfigInstaller->installDefaultConfig('module',
'recipes_magazin...')
#14
/var/www/web/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php(83):
Drupal\Core\Extension\ModuleInstaller->install(Array, true)
#15
/var/www/web/profiles/contrib/contenta_jsonapi/contenta_jsonapi.profile(40):
Drupal\Core\ProxyClass\Extension\ModuleInstaller->install(Array)
#16 [internal function]:
contenta_jsonapi_install_configure_form_submit(Array,
Object(Drupal\Core\Form\FormState))
#17 /var/www/web/core/lib/Drupal/Core/Form/FormSubmitter.php(111):
call_user_func_array('contenta_jsonap...', Array)
#18 /var/www/web/core/lib/Drupal/Core/Form/FormSubmitter.php(51):
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array,
Object(Drupal\Core\Form\FormState))
#19 /var/www/web/core/lib/Drupal/Core/Form/FormBuilder.php(589):
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array,
Object(Drupal\Core\Form\FormState))
#20 /var/www/web/core/lib/Drupal/Core/Form/FormBuilder.php(485):
Drupal\Core\Form\FormBuilder->processForm('install_configu...',
Array, Object(Drupal\Core\Form\FormState))
#21 /var/www/web/core/includes/install.core.inc(951):
Drupal\Core\Form\FormBuilder->submitForm('Drupal\\Core\\Ins...',
Object(Drupal\Core\Form\FormState))
#22 /var/www/web/core/includes/install.core.inc(606):
install_get_form('Drupal\\Core\\Ins...', Array)
#23 /var/www/web/core/includes/install.core.inc(562):
install_run_task(Array, Array)
#24 /var/www/web/core/includes/install.core.inc(120):
install_run_tasks(Array)
#25 /usr/local/src/drush/includes/drush.inc(726):
install_drupal(Object(Composer\Autoload\ClassLoader), Array)
#26 /usr/local/src/drush/includes/drush.inc(711):
drush_call_user_func_array('install_drupal', Array)
#27 /usr/local/src/drush/commands/core/drupal/site_install.inc(84):
drush_op('install_drupal', Object(Composer\Autoload\ClassLoader),
Array)
#28 /usr/local/src/drush/commands/core/site_install.drush.inc(254):
drush_core_site_install_version('contenta_jsonap...', Array)
#29 /usr/local/src/drush/includes/command.inc(422):
drush_core_site_install('contenta_jsonap...')
#30 /usr/local/src/drush/includes/command.inc(231):
_drush_invoke_hooks(Array, Array)
#31 /usr/local/src/drush/includes/command.inc(199):
drush_command('contenta_jsonap...')
#32 /usr/local/src/drush/lib/Drush/Boot/BaseBoot.php(67):
drush_dispatch(Array)
#33 /usr/local/src/drush/includes/preflight.inc(66):
Drush\Boot\BaseBoot->bootstrap_and_dispatch()
#34 /usr/local/src/drush/drush.php(12): drush_main()
#35 {main}
e0ipso’s picture

Status: Active » Needs review
StatusFileSize
new1013 bytes

Make sure the service exists.

  • e0ipso committed c816076 on 8.x-2.x
    Issue #2982133 by Wim Leers, e0ipso: No longer works with JSON API >=1....

Status: Needs review » Needs work

The last submitted patch, 31: 2982133--31.patch, failed testing. View results

e0ipso’s picture

Status: Needs work » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

campsjos’s picture

Hi all,
I getting the same error as #19 after setting a Timestamp or Date Time Field Enhancer to a date field:
Trait 'Shaper\\DataAdaptor\\DataAdaptorValidatorTrait' not found in /xxxx/web/modules/jsonapi_extras/src/Plugin/ResourceFieldEnhancerBase.php on line 25
@e0ipso mentioned that this module should be installed via composer, is that true? It can't be installed via backend?
I installed both JSON API and JSON API Extras modules today so all the patches posted here are already commited.
I'm really stuck on this, can anyone give a helping hand? :)

jsonapi: 8.x-1.23+0-dev
jsonapi_extras: 8.x-2.5
drupal: 8.5.3

Thanks.

e0ipso’s picture

Status: Closed (fixed) » Active

Many hours went into debugging this. This broke Contenta CMS installer using CLI.

e0ipso’s picture

Status: Active » Needs review
StatusFileSize
new1.37 KB

  • e0ipso committed d746ffc on 8.x-2.x
    Issue #2982133 by e0ipso: Do not rebuild container during CLI install
    
e0ipso’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.