Problem/Motivation
It's very hard to understand routing in the REST module, and it's very brittle, because:
ResourceBase
only sets_format
for GET route, should also do so for POST/PATCH/DELETE routes.ResourceBase
generates one route per method for POST/PATCH/DELETE, but one route per method+format for GET. This should be made consistent.ResourceBase
generates individual GET routes for every available serialization format, not just the ones that are allowed by the configuration, and thenResourceRoutes::alter()
removes those that are not acceptable by the configuration.ResourceBase
sets_content_type_format
for PATCH/POST, but it should actually also set_format
.ResourceBase
sets_content_type_format
not to the allowed formats for that particular REST resource (as per therest.settings
configuration), but to all acceptable serialization formats, and then has validation for it in\Drupal\rest\RequestHandler::handle()
.ResourceRoutes::alter()
is doing configuration verification.ResourceRoutes::alter()
assumes_format
has only ever one format listed, even though multiple can be listed. This blows up as soon as any custom@RestResource
plugin specifies multiple formats, which it can by not usingResourceBase::routes()
.ResourceRoutes::alter()
sets_csrf_request_header_token
on all routes, including GET routes. This is harmless, but it causes extra, unnecessary computations on those requests. And it makes the route more confusing to debug.RequestHandler::handle()
assumes_format
is always set, and always has a single value — and in case it's not set, its ultimate solution is "just pick JSON". But it's not guaranteed to have a single value… nor does it even always have a value. And in fact, PATCH/POST routes do not have_format
set. So any PATCH/POST request will actually result in a JSON response, even if you explicitly specify?_format=xml
!— fixed by #2662284: Return complete entity after successful PATCHHandling of 4xx responses is done in— fixed by #2739617: Make it easier to write on4xx() exception subscribers + #2805281: ?_format=hal_json error responses are application/json, yet should be application/hal+json + #2813853: RequestHandler has its own error handling rather than leaving it to KernelEvents::EXCEPTION event subscribersRequestHandler::handle()
instead of in aKernelEvents::EXCEPTION
event subscriber. This prevents Basic Auth 401 responses from being sent, and means REST has its own system in parallel to Symfony's/Drupal core's.- …
Clearly, this leaves us in a state where we keep finding bizarre bugs.
Proposed resolution
Refactor REST's routing for better maintainability.
Remaining tasks
- Find agreement.
- Do it.
- Review it.
- Commit it.
User interface changes
None.
API changes
None.
Data model changes
None.