Problem/Motivation

ViewsPathTranslatorSubscriber::onPathTranslation() builds a JSON:API Views route name from the resolved view and passes it straight to Url::fromRoute():

$parts = [
  'jsonapi_views',
  $match_info['view_id'],
  $match_info['display_id'],
];
$jsonapi_views_route = implode('.', $parts);
$resolved_jsonapi_views_url = Url::fromRoute($jsonapi_views_route, [], ['absolute' => TRUE])->toString(TRUE);

JSON:API Views does not register a route for every view. Drupal\jsonapi_views\Routing\Routes::routes() skips a view that has no base entity type, and a view whose base entity type has no bundle with a JSON:API resource type. For a skipped view that route name does not exist, Url::fromRoute() throws Symfony\Component\Routing\Exception\RouteNotFoundException, nothing catches it, and the whole /router/translate-path request returns a 500 even though the view itself resolved correctly.

Core ships a view of this kind. "Recent log messages" uses watchdog as its base table, which is not an entity table, so JSON:API Views gives it no route.

Expected: a 200 describing the resolved view, with the jsonapi_views key left out, because this view has no JSON:API Views endpoint.

Actual: a 500 from the uncaught exception.

This is not the "Expose via JSON:API" display setting. Route registration does not read that setting. Exposure is enforced later at runtime in ViewsResource::view() through isExposed(), so turning it off does not cause this, and neither will the opt-in default change in https://www.drupal.org/i/3587946.

Steps to reproduce

1. Install Drupal with the standard profile, which enables Views and Database Logging.
2. Enable druxt, decoupled_router and jsonapi_views.
3. Request /router/translate-path?path=/admin/reports/dblog&_format=json.
4. Observe a 500 instead of a description of the view.

Any view over a base table that is not an entity table behaves the same way.

Proposed resolution

Catch RouteNotFoundException around the lookup and leave the jsonapi_views key out of the response. A view with no JSON:API Views endpoint is a normal state, not an error, so the view data, the jsonapi block and the 200 response all stay as they are.

Remaining tasks

- Confirm the /admin/reports/dblog path on a running site. The mechanism itself is proven: a kernel test adds a view with no base entity type, and asserts a 200 with no jsonapi_views key. That assertion only passes if the route really is absent and the exception really was thrown and caught, so both the premise and the fix are covered. The specific core view named above has not been requested end to end.
- Review the merge request.
- Merge and ship in 1.2.2, alongside https://www.drupal.org/i/3618675.

User interface changes

None.

API changes

None. The jsonapi_views key is not removed from any response that previously carried it, because the affected requests returned no response at all.

Data model changes

None.

Related

- https://www.drupal.org/i/3558380 and https://www.drupal.org/i/3467742, earlier fixes in this same method.
- https://www.drupal.org/i/3176615, the same defect in Decoupled Router's own JSON:API individual route lookup.
- https://www.drupal.org/i/3144602, which moves this subscriber into Decoupled Router 2.1.0. The guard needs to travel with it.

Issue fork druxt-3618677

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

deciphered created an issue. See original summary.

deciphered’s picture

Status: Active » Needs review

  • deciphered committed 9893bbf3 on 1.2.x
    fix(#3618677): guard the jsonapi_views route lookup in the Views...
deciphered’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

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