Quantcast
Channel: Issues for Drupal core
Viewing all articles
Browse latest Browse all 292173

Make ContentNegotiation a "internal" service, used only by the router, so that core or contrib can implement real negotiation

$
0
0

Problem/Motivation

  • Drupal\Core\ContentNegotiation has a @todo saying "Replace this class with a real content negotiation library".
  • #1505080: [META] Content Negotiation for Accept Headers is the issue for doing that, though it's not clear whether that can still happen in time for core or not.
  • In any case, the API of that class is fundamentally flawed, so should be changed (ideally, before the July 1 API freeze), so that we can either implement a real content negotiation library in core after API freeze, or do it in contrib.
  • The flaw is that ContentNegotiation::getContentType($request) is expected to return a string: meaning, a known format. However, which format is appropriate is a question whose answer depends on routing information. For example, if the Accept header is text/html, */* and there's a route for the requested URL that can return HTML, then the answer is 'html', but if there's only a route for the requested URL that can return json, then the answer is 'json'. And if there are multiple routes for the requested URL: one that can return json and one that can return xml, then the routing system may want to have a say as to which one is higher priority (the Accept header may also include priority information, but in the example above, it doesn't). The current implementation of ContentNegotiation checks only against formats statically defined as potentially available, but takes no consideration of routing information to determine what's available for the requested URL.
  • We currently have a hack in RestExport::initDisplay() to get around this problem for its own use case: it ignores ContentNegotiation::getContentType() if it returns 'html', since it knows that its entire purpose is to return something other than 'html'. However, a controller needing to overrule the content negotiation service is an indication of the content negotiation service being broken.
  • On a DX note, getContentType() is a poor method name, because the request object also has a getContentType() method, but that one returns the content type of the request body, which has nothing to do with the desired format of the response.

Proposed resolution

  • Symfony's Request class already has a getRequestFormat() method whose job is to return the single desired format of the response, as determined by routing or whatever else can act on a $request. Everywhere in Drupal that we currently call $this->negotiation->getContentType($request) should be changed to call $request->getRequestFormat() instead. At this time, that's:
    - AjaxEnhancer::enhance()
    - ContentControllerEnhancer::enhance()
    - EntityRouteEnhancer::enhance()
    - FormEnhancer::enhance()
    - drupal_get_js()
    - ViewSubscriber::onView()
    - OverlaySubscriber::onRequest()
    - ExceptionController::execute()
    - RestExport::initDisplay().
  • The only thing that should interact with the content negotiation service directly is the routing system itself. We already have a 'mime_type_matcher' service that filters out routes whose format requirement is incompatible with the Accept header. What we need to add is to then somehow let the content negotiation service pick the best match, or provide information to something in the routing system that can then pick the best match. And then based on that, the routing system needs to either set the '_format' attribute of the $request, or call $request->setRequestFormat() (I'm not too clear on the pros/cons of whether to do the former, latter, or both).

Remaining tasks

  • Figure out the actual API we want ContentNegotiation to have. People involved in #1505080: [META] Content Negotiation for Accept Headers, who know how those libraries work, might have input on this.
  • Add something into the routing flow that uses this API to do what's above in "Proposed resolution".

User interface changes

None.

API changes

See above.

#1505080: [META] Content Negotiation for Accept Headers


Viewing all articles
Browse latest Browse all 292173

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>