Problem/Motivation

First reported at #2866736: JSON API should reply with a 409 status when sending a POST request to an existing entity for the JSON API contrib module.

Also see https://httpstatuses.com/409

Proposed resolution

Return a 409 for POST requests to an existing resource.

Remaining tasks

Make it work.

User interface changes

None.

API changes

None.

Data model changes

None.

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new1.02 KB

The goal is to make this test pass.

Status: Needs review » Needs work

The last submitted patch, 2: 2870649-2.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new1.96 KB

Let's see whether this is it.

Status: Needs review » Needs work

The last submitted patch, 4: 2870649-4.patch, failed testing.

dawehner’s picture

StatusFileSize
new1.45 KB
new1.96 KB

Note: I do believe the test is in the wrong place. It should be after assigning the permission.

This doesn't fix the problem yet though.

wim leers’s picture

I think that this cannot be implemented in EntityResource::post(). Because the 409 must be thrown when POSTing to /node/1, not when POSTing to /node. But for the /node/1 URL, only GET, PATCH and DELETE routes exist.

Therefore I think the only way to implement this is via a \Drupal\Core\Routing\RoutingEvents::ALTER event subscriber, which modifies all REST GET routes to also accept POST and then adding a route filter that explicitly detects this case ("POSTing to a GET-only route") and then throws a 409 error response exception.

If I'm right, then this is ridiculously convoluted, and probably not worth it…

dawehner’s picture

I think that this cannot be implemented in EntityResource::post(). Because the 409 must be thrown when POSTing to /node/1, not when POSTing to /node. But for the /node/1 URL, only GET, PATCH and DELETE routes exist.

You are absolutely right.

If I'm right, then this is ridiculously convoluted, and probably not worth it…

It is again a tradeoff of features vs. maintainablity. Maybe it would be worth to have these kind of things in contrib, but yeah I agree its tricky.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new9.02 KB
new2.46 KB

Maybe we could just go with the following ...

wim leers’s picture

StatusFileSize
new1.06 KB
new9.94 KB

That's very clever! :)

So let's add back the test coverage I wrote in #2, to verify that this is working as intended.

wim leers’s picture

Related issues: +#2775479: Try to remove the "map HEAD to GET" logic in \Drupal\rest\RequestHandler::handle()
StatusFileSize
new2.08 KB
new10.97 KB

#10 is failing because of a tiny bug in #9.

But then there is another problem: because the "GET" route now also supports the "POST" method, an important assertion that was added in #2775479: Try to remove the "map HEAD to GET" logic in \Drupal\rest\RequestHandler::handle() no longer holds true.

This should be green!

wim leers’s picture

Title: REST should respond with a 409 for a POST request to an existing entity » [PP-1] REST should respond with a 409 for a POST request to an existing entity
Status: Needs review » Postponed
Related issues: +#2720233: Use arguments resolver in RequestHandler to have consistent parameter ordering

And clearly this patch is blocked on #2720233: Use arguments resolver in RequestHandler to have consistent parameter ordering: it needs the improvements there, otherwise this can't work:

+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -114,12 +116,19 @@ public static function create(ContainerInterface $container, array $configuratio
-  public function get(EntityInterface $entity) {
+  public function get(EntityInterface $entity, Request $request) {
wim leers’s picture

Issue tags: +Needs change record

This will also need a change record to inform developers that this is now supported.

dawehner’s picture

Thank you for using the right $route :)

And clearly this patch is blocked on #2720233: Use arguments resolver in RequestHandler to have consistent parameter ordering: it needs the improvements there, otherwise this can't work:

This is one of those cases where doing things right, actually helps :)

wim leers’s picture

This is one of those cases where doing things right, actually helps :)

:)

#11 wasn't green though! There are failures for all ItemResourceTestBase and EntityTestResourceTestBase tests (6 each), plus 2 failures in RequestHandlerTest.

Also… while thinking some more about this yesterday evening, I realized this is not yet sufficient:

+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -114,12 +116,19 @@ public static function create(ContainerInterface $container, array $configuratio
-  public function get(EntityInterface $entity) {
+  public function get(EntityInterface $entity, Request $request) {
+    if ($request->getMethod() === 'POST') {
+      throw new ConflictHttpException('POSTING to an already existing entity resource');
+    }

+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -869,6 +869,11 @@ public function testPost() {
+    // DX: 409 when POSTing to an existing entity.
+    $response = $this->request('POST', $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]), $request_options);
+    $this->assertResourceErrorResponse(409, 'POSTING to an already existing entity resource', $response);

i.e. this is testing POSTing to /node/5 results in a failure. But what we want, is that POSTing to /node results in a failure, by checking whether the UniqueField constraint has been violated!

I guess that could be a follow-up, but it might be better to handle it here, because it's conceptually about the same thing. Perhaps our implementation becomes better because of it, because we'll be throwing a 409 HTTP exception from two places.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.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: Task » Feature request
dawehner’s picture

#11 wasn't green though!

Maybe you just had some level of f.lux enabled on your laptop :)

wim leers’s picture

Title: [PP-1] REST should respond with a 409 for a POST request to an existing entity » REST should respond with a 409 for a POST request to an existing entity
Status: Postponed » Needs work

#12 said this was blocked on #2720233: Use arguments resolver in RequestHandler to have consistent parameter ordering, but it hasn't been blocked on that for a long while, because that landed in September 2017!

wim leers’s picture

#19: haha :P Thanks for bubbling this issue to the top again, it's how I noticed #20!

wim leers’s picture

Status: Needs work » Needs review
Related issues: +#2858482: Simplify REST routing: disallow requesting POST/PATCH in any format, make consistent
StatusFileSize
new961 bytes
new4.98 KB

Most of this patch was committed in #2720233: Use arguments resolver in RequestHandler to have consistent parameter ordering. Which means this patch can become a lot smaller! 🎉

In the mean time, #2858482: Simplify REST routing: disallow requesting POST/PATCH in any format, make consistent got committed, which massively conflicted with this patch's changes in ResourceBase. The attached interdiff is not really a diff. It shows the change we're making to ResourceBase as of this new patch.

Status: Needs review » Needs work

The last submitted patch, 22: 2870649-21.patch, failed testing. View results

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

boby_ui’s picture

I have a problem with register api with d8, its randomly causing 409 error? what does this means? is it server configurations or?

jhedstrom’s picture

Status: Needs work » Needs review

This is a reroll of #22 against the latest 8.8.x.

jhedstrom’s picture

StatusFileSize
new4.24 KB

Attaching the patch would help :)

Status: Needs review » Needs work

The last submitted patch, 28: 2870649-28.patch, failed testing. View results

jhedstrom’s picture

Status: Needs work » Needs review
StatusFileSize
new787 bytes
new4.28 KB

The reason a 403 instead of a 409 was happening in all those failed tests was that the test user didn't have access to view the entity in question, and that access check happens long before the 409 change in this patch. This gets tests passing by granting that access.

Status: Needs review » Needs work

The last submitted patch, 30: 2870649-30.patch, failed testing. View results

dhanlal’s picture

Assigned: Unassigned » dhanlal

i working on this issue

dhanlal’s picture

Assigned: dhanlal » Unassigned

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.