Drupal: 8.5.1

Stack trace:

Error: Call to a member function access() on null in /var/www/docroot/modules/contrib/jsonapi/src/Controller/EntityResource.php on line 791 #0 /var/www/docroot/modules/contrib/jsonapi/src/Controller/EntityResource.php(379): Drupal\\jsonapi\\Controller\\EntityResource->relationshipAccess(Object(Drupal\\node\\Entity\\Node), 'view', 'relationships')\n#1 [internal function]: Drupal\\jsonapi\\Controller\\EntityResource->getRelated(Object(Drupal\\node\\Entity\\Node), 'relationships', Object(Symfony\\Component\\HttpFoundation\\Request))\n#2 /var/www/docroot/modules/contrib/jsonapi/src/Controller/RequestHandler.php(145): call_user_func_array(Array, Array)\n#3 /var/www/docroot/core/lib/Drupal/Core/Render/Renderer.php(582): Drupal\\jsonapi\\Controller\\RequestHandler->Drupal\\jsonapi\\Controller\\{closure}()\n#4 /var/www/docroot/modules/contrib/jsonapi/src/Controller/RequestHandler.php(146): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))\n#5 [internal function]: Drupal\\jsonapi\\Controller\\RequestHandler->handle(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Drupal\\jsonapi_extras\\ResourceType\\ConfigurableResourceType))\n#6 /var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)\n#7 /var/www/docroot/core/lib/Drupal/Core/Render/Renderer.php(582): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#8 /var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))\n#9 /var/www/docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)\n#10 /var/www/docroot/vendor/symfony/http-kernel/HttpKernel.php(151): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#11 /var/www/docroot/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw(Object(Symfony\\Component\\HttpFoundation\\Request), 1)\n#12 /var/www/docroot/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\\Component\\HttpKernel\\HttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#13 /var/www/docroot/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\\Core\\StackMiddleware\\Session->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#14 /var/www/docroot/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#15 /var/www/docroot/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\\page_cache\\StackMiddleware\\PageCache->pass(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#16 /var/www/docroot/modules/contrib/jsonapi/src/StackMiddleware/FormatSetter.php(40): Drupal\\page_cache\\StackMiddleware\\PageCache->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#17 /var/www/docroot/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\\jsonapi\\StackMiddleware\\FormatSetter->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#18 /var/www/docroot/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#19 /var/www/docroot/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#20 /var/www/docroot/core/lib/Drupal/Core/DrupalKernel.php(664): Stack\\StackedHttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#21 /var/www/docroot/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#22 {main}

Comments

BR0kEN created an issue. See original summary.

wim leers’s picture

Assigned: Unassigned » gabesullice

I'd swear I've already seen an issue much like this one! Perhaps @gabesullice recalls.

br0ken’s picture

Issue summary: View changes
e0ipso’s picture

I don't recall .../relationships is a valid endpoint according to the spec. We should be throwing a 404 for those.

br0ken’s picture

StatusFileSize
new998 bytes

This test should pass when the patch will be provided.

wim leers’s picture

Assigned: gabesullice » Unassigned
Status: Active » Needs work

Thanks for writing test coverage, @BR0kEN! It's clear to me now what the problem is: …/relationships is invalid, …/relationships/<name of entity reference field> is valid. Makes sense.

I'm happy to write the fix, unless you want to, @BR0kEN?

br0ken’s picture

Unfortunately I don't know a location where it should be placed. Therefore I'd be happy if you proceed.

wim leers’s picture

Title: A call to "api/node/url/UUID/relationships" ends in a fatal error » Spec Compliance: requests "<resource>/relationships" should result in 400 response, currently results in fatal PHP error
Assigned: Unassigned » wim leers
Issue tags: +DX (Developer Experience)

Working on fix.

wim leers’s picture

Title: Spec Compliance: requests "<resource>/relationships" should result in 400 response, currently results in fatal PHP error » Spec Compliance: requests to "<resource>/relationships" should result in 400 response, currently results in fatal PHP error
wim leers’s picture

Title: Spec Compliance: requests to "<resource>/relationships" should result in 400 response, currently results in fatal PHP error » Spec Compliance: requests to "<resource>/relationships" should result in 404 response, currently results in fatal PHP error

Oops.

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review
StatusFileSize
new2.51 KB
new2.97 KB

I found the root cause:

  • The relationship route's path looks like this:
    /jsonapi/node/{node}/relationships/{related}
    
  • The related route's path looks like this:
    /jsonapi/node/{node}/{related}
    

Consequently, when you try to access /jsonapi/node/{node}/relationships, that matches the related route, not the relationship route; and matches {related} with "relationships".

The solution is quite simple: specify an explicit /jsonapi/node/{node}/relationships route, whose controller does nothing but throw a helpful 404 exception. But that requires adding a new route. I did some digging/searching, and ended up going with https://symfony.com/doc/3.4/routing/optional_placeholders.html instead. Slightly more elegant IMHO.

Let's see what the other maintainers think!

gabesullice’s picture

This sort of instability is one of my primary reasons for pushing #2953346: Define related/relationship routes per field, not dynamically (with route parameters that need validating).

There's no real reason for us to have field names as route parameters any more. It just means we have more edge cases and less predictability.

Since this isn't really critical, I'd rather just wait to land that one. Then this problem disappears and we don't have to have code and tests for a non-issue.

wim leers’s picture

I agreed with you over at #2953346-9: Define related/relationship routes per field, not dynamically (with route parameters that need validating). I do think that #2953346 should still inherit the test coverage from #5. Agreed?

gabesullice’s picture

Can't hurt. Agreed.

wim leers’s picture

Status: Needs review » Closed (duplicate)