Skip to content

Conversation

@GautierDele
Copy link
Member

@GautierDele GautierDele commented Sep 18, 2025

closes #178

Summary by CodeRabbit

  • New Features

    • Bulk delete now validates each requested item exists, preventing any partial deletions.
    • Returns a clear 422 validation error with item-specific feedback when any provided ID is invalid.
  • Tests

    • Added tests to confirm 422 responses and that no deletions occur when a non-existent ID is included in bulk delete requests.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Walkthrough

Adds per-item existence validation and distinct check for bulk delete requests by constructing the resource model in DestroyRequest::destroyRules; adds a feature test verifying a 422 response and no deletions when any provided ID does not exist.

Changes

Cohort / File(s) Summary
Request validation: destroy rules
src/Http/Requests/DestroyRequest.php
Adds use Illuminate\Validation\Rule;, creates $model = $resource::newModel() in destroyRules, and updates resources.* validation to include distinct and Rule::exists($model->getTable(), $model->getKeyName()) while keeping the resources array rule.
Feature tests: delete operations
tests/Feature/Controllers/DeleteOperationsTest.php
Adds test_deleting_a_non_existing_model() which sends a bulk delete with a non-existent ID and an existing ID, expects HTTP 422 with a validation error on resources.0, and asserts the existing model remains in the database.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant Ctl as Delete Controller
  participant Req as DestroyRequest (validator)
  participant DB as Database

  C->>Ctl: DELETE /resource { resources: [id_missing, id_existing] }
  Ctl->>Req: Validate payload
  Req->>DB: For each resources.* => check distinct and exists(table, key)
  alt Any ID missing
    Req-->>Ctl: Validation fails (422, errors.resources.*)
    Ctl-->>C: 422 Unprocessable Entity
  else All IDs exist
    Ctl->>DB: Delete rows
    Ctl-->>C: 200/204 Success
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Fix/delete unexisting resource" concisely reflects the main intent—preventing deletion when supplied resource IDs do not exist—and matches the changes which add validation and a test for non‑existing IDs. It is directly related to the changeset though slightly informal in wording.
Linked Issues Check ✅ Passed The PR implements per‑item existence validation (Rule::exists on resources.*) and adds a test that expects a validation error and HTTP 422 when a non‑existing ID is included, and it asserts no deletion occurs, which directly addresses the core concern in linked issue [#178] of the API returning 200 for deletes that include missing resources. The PR returns a 422 validation error rather than a 404, but this still resolves the reported incorrect success behavior and prevents unintended deletions.
Out of Scope Changes Check ✅ Passed All reported changes are limited to DestroyRequest validation and an associated feature test (tests/Feature/Controllers/DeleteOperationsTest.php); there are no other modified files or signature changes in the provided summary, so I find no out‑of‑scope or unrelated changes.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/delete-unexisting-resource

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97e7e59 and 3c47b5c.

📒 Files selected for processing (2)
  • src/Http/Requests/DestroyRequest.php (2 hunks)
  • tests/Feature/Controllers/DeleteOperationsTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/Feature/Controllers/DeleteOperationsTest.php
  • src/Http/Requests/DestroyRequest.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Tests on PHP 8.4 with Laravel ^11.0 and pgsql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and pgsql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^11.0 and mysql
  • GitHub Check: Tests on PHP 8.3 with Laravel ^11.0 and pgsql
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and sqlite
  • GitHub Check: Tests on PHP 8.4 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^12.0 and sqlite
  • GitHub Check: Tests on PHP 8.3 with Laravel ^11.0 and sqlite
  • GitHub Check: Tests on PHP 8.3 with Laravel ^12.0 and pgsql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^12.0 and mysql
  • GitHub Check: Tests on PHP 8.2 with Laravel ^11.0 and pgsql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
src/Http/Requests/DestroyRequest.php (3)

36-44: Good existence check; add distinct/min:1 and prefer model-aware exists to avoid connection/table drift.

  • Add min:1 so empty arrays fail fast.
  • Add distinct to prevent duplicate IDs.
  • Use Rule::exists(get_class($model), …) so the model’s connection/table are honored.
  • Optional: bail on each item to skip DB lookups if a duplicate is detected first.

Apply:

-        return [
-            'resources' => [
-                'required', 'array',
-            ],
-            'resources.*' => [
-                Rule::exists($model->getTable(), $model->getKeyName()),
-            ],
-        ];
+        return [
+            'resources' => [
+                'required', 'array', 'min:1',
+            ],
+            'resources.*' => [
+                'bail', 'distinct',
+                Rule::exists(get_class($model), $model->getKeyName()),
+            ],
+        ];

36-44: Consider scoping the exists rule to the resource’s visibility to avoid ID enumeration.

If this API is multi‑tenant or otherwise scoped, plain exists can leak whether an ID exists outside the caller’s scope. If your Resource exposes a query scope (e.g., indexQuery or similar), apply it to the Exists rule via using()/where().

Would you like me to wire this to the appropriate scope on Resource (if available) so validation only passes for records visible to the caller?


23-33: Docblock param type mismatch.

The docblock says “@param resource” (PHP built‑in) but the signature is Resource. Update for accuracy.

-     * @param resource $resource
+     * @param Resource $resource
tests/Feature/Controllers/DeleteOperationsTest.php (3)

59-79: Naming nit: “non_existing” reads cleaner than “not_existing”.

Purely cosmetic; feel free to skip.

-    public function test_deleting_a_not_existing_model(): void
+    public function test_deleting_a_non_existing_model(): void

59-79: Optional: add a duplicate‑ID case once distinct is enforced.

If you adopt distinct, add a test to assert a validation error for duplicate IDs and that no deletions occur.

I can add a focused test method mirroring this one with a duplicated $model->getKey().


59-79: Prefer built‑in validation assertions (use assertInvalid when available)

Replace assertExactJsonStructure with assertInvalid(['resources.0']) in this test; assertExactJsonStructure is used across many tests — perform a project‑wide replacement only after confirming your Laravel version supports assertInvalid (fallback: assertJsonValidationErrors).

-        $response->assertStatus(422);
-        $response->assertExactJsonStructure(['message', 'errors' => ['resources.0']]);
+        $response->assertStatus(422);
+        $response->assertInvalid(['resources.0']);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bcaba0 and 97e7e59.

📒 Files selected for processing (2)
  • src/Http/Requests/DestroyRequest.php (2 hunks)
  • tests/Feature/Controllers/DeleteOperationsTest.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/Feature/Controllers/DeleteOperationsTest.php (3)
tests/Support/Database/Factories/ModelFactory.php (1)
  • ModelFactory (8-29)
tests/Support/Models/Model.php (1)
  • Model (10-112)
tests/Support/Policies/GreenPolicy.php (1)
  • GreenPolicy (8-100)
src/Http/Requests/DestroyRequest.php (1)
src/Http/Resource.php (1)
  • newModel (61-67)
🔇 Additional comments (1)
src/Http/Requests/DestroyRequest.php (1)

5-5: Import for Rule is correct.

Needed for the new validation; no issues here.

Comment on lines 36 to 44
$model = $resource::newModel();

return [
'resources' => [
'required', 'array',
],
'resources.*' => [
Rule::exists($model->getTable(), $model->getKeyName()),
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

422 vs 404 semantics — confirm product intent.

This change makes non‑existent IDs return 422 (validation). The linked issue mentions “e.g., 404”. For bulk DELETE via body, 422 is reasonable; just confirm this is the intended contract.


🏁 Script executed:

#!/bin/bash
# Find any docs/tests expecting 404 for non-existent deletes
rg -n -C2 -i 'delete.+(404|not found)|assertStatus\(\s*404\s*\)|assertNotFound' --type=php

Length of output: 336


422 vs 404 semantics — confirm product intent.

Tests assert 404 for non‑existent deletes, but this change causes a 422 validation response; reconcile contract.

  • Tests: tests/Feature/Controllers/ActionsOperationsTest.php:103 (assertStatus(404)).
  • Code: src/Http/Requests/DestroyRequest.php (lines 36–44) — 'resources.*' uses Rule::exists(...) causing validation failure -> 422.

Either restore 404 semantics (handle missing IDs and return 404) or update tests/docs to accept 422.

@GautierDele GautierDele merged commit d52b512 into main Sep 18, 2025
21 checks passed
@GautierDele GautierDele deleted the fix/delete-unexisting-resource branch September 18, 2025 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

response status error

3 participants