I created a REST resource for GETing custom made data by an external site. This works fine if I provide an empty string as Basic HTTP Auth in the request, but fails when providing data for an existing user. I can also reproduce this with the Watchdog database log (/dblog/{id}) endpoint that comes with core.

Steps to reproduce:

1. Enable the following core modules:

  • HTTP Basic Authentication
  • RESTful Web Services
  • Database Logging

2. For easy REST config add / enable:

  • REST UI

3. Goto: admin/config/services/rest and enable the resource "Watchdog database log"

4. Goto: /admin/config/services/rest/resource/dblog/edit and configure the resource for using basic_auth as "Authentication provider"

5. Access the endpoint with Postman or a similar tool. eg.: http://MY.DOMAIN/dblog/37035?_format=json Use the login credentials for user 1 as basic auth header. You get an NotAcceptableHttpException as resulting data you see "No route found for the specified format html."

Problem

Before the request is even handed over to the resource plugin that handles the json response it is always checked if there is a route for returning html. For this path such a route is not existent. Therefore in \Drupal\Core\Routing\RequestFormatRouteFilter::filter the execution stops with an exception and the json is never returned. Why and where the decision is made to run into this check is unclear to me. But creating a route /dblog/{id} with some bogus return fixes the problem as the first filter call is then passed and also gets passed a few steps later if it is checked if there is a component that returns json format.

Example:

After returning something on the normal route without _format parameter everything works.

  /**
   * Controller callback for the api route as there is an error if there is no
   * response controller for html format.
   *
   * @return mixed
   */
  public function noHtml() {

    $output['message'] = array(
      '#markup' => 'No output here.',
    );

    return $output;
  }

Solution

Don't check for format HTML if another format is already provided in the URL?

Comments

marcusx created an issue. See original summary.

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

http://MY.DOMAIN/dblog/37035?_format=json + No route found for the specified format html. = makes no sense :)
You're requesting JSON (and doing so correctly), yet the server is seeing you're requesting HTML.

This looks like it can be a bug in the routing system, or in REST's routes. I've seen many bugs in either.

On the other hand, you'd think this would've been reported a long time ago. However, few people use the dblog REST resource. Most use the entity resource. And, sure enough, entities do render HTML at /node/1, dblog does not render HTML at /dblog/{id}. So I think it's quite plausible you've indeed found a major bug. It's certainly a routing bug, but we'll have to see where exactly something is wrong.

Just to be sure: can you export your configuration and post it here?

wim leers’s picture

Title: REST resource endpoint returns "NotAcceptableHttpException" if used with BasicAuth and no regular page route defined » REST resource endpoint returns "NotAcceptableHttpException" if no HTML route is defined at the same URL

Going out on a limb and updating the issue title to describe what I strongly suspect to be the problem. I don't think the authentication aspect here is relevant to the bug.

manu manu’s picture

I may have the same issue, using entityqueryapi 8.x-1.0-alpha8 and core 8.2.x-dev. It began breaking recently, maybe last week.

In short and based on previous comments, adding a html format to json in the requirements section made it somewhat working:

entityqueryapi.collections_controller_content:
  path: 'entity/{entity_type}'
  [...]
  requirements:
    _custom_access: '\Drupal\entityqueryapi\Controller\EntityQueryApiController::access'
    _format: 'json|html'
    _method: 'GET'

This module is quite simple and I suspect it is not responsible for this issue. It's very similar to any custom module defining a route with only a json format supported.

Drupal\Core\Routing\RequestFormatRouteFilter::filter() gets indeed the default html format from $request instead of json.

If it helps, here is a gist containing a backtrace until Drupal\Core\Routing\RequestFormatRouteFilter::filter().

manu manu’s picture

Status: Postponed (maintainer needs more info) » Active
manu manu’s picture

Note that I experienced this problem with a custom Rest resource, too.
I will try to package a simple module to reproduce this on a clean install.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

wim leers’s picture

Category: Bug report » Support request
Priority: Major » Normal
Status: Active » Closed (cannot reproduce)

I followed the exact steps to reproduce in the IS. I can't reproduce this. The many fixes to the REST module (and related subsystems) in the past few months has likely fixed this. Update to Drupal 8.3 and it should be solved :)

manu manu’s picture

All right Wim, I will test when I will come back to the project that was having the issue :-)