Repository: Lomkit/laravel-rest-api (php)

Issue:
Potential Issue with Unchecked 'mutate' Key in mutate Method
### Laravel Rest Api Version

2.7

### Laravel Version

11.9

### PHP Version

8.2

### Database Driver & Version

_No response_

### Description

Hello,

I want to report a potential issue in the `mutate` method that could affect the robustness of the code.

### Problem Description

The current implementation of the `mutate` method assumes the existence of the `mutate` key in the `$parameters` array without prior verification. This assumption could lead to an `Undefined index: mutate` error if the `$parameters` array is empty or does not contain this key.

Here is the relevant code snippet:

```php
public function mutate(array $parameters = [])
{
    $operations = [
        'created' => [],
        'updated' => [],
    ];

    foreach ($parameters['mutate'] as $parameter) {
        $operations[
            $this->mutateOperationsVerbose[$parameter['operation']]
        ][] = $this->applyMutation($parameter)->getKey();
    }

    return $operations;
}
```

Source: [Lomkit/laravel-rest-api - PerformMutation.php#L35](https://github.com/Lomkit/laravel-rest-api/blob/5ccdac89b99e2e54e71b2cf841fea7f53893eabb/src/Query/Traits/PerformMutation.php#L35)

### Impact

This can result in runtime errors, particularly in cases where the input parameters are malformed or incomplete, reducing the resilience of the application.

### Suggested Improvement

Adding a check to ensure the `mutate` key exists and is an array before accessing it would prevent this issue.

Thank you for considering this report.

Best regards, 

### Steps To Reproduce

Send POST with error in body

```
POST {{host}}api/entity/mutate/
content-type: application/json

{
  "mutate": [
    {
      "operation": "update",
      "key": 1,
      "relations": {
        "status": {
          "operation": "update",
          "key": 1, //<= wrong comma 
        }
      }
    }
  ]
}
```

Pull request:
:bug: mutate crash when no mutate key provided
closes #137 

Patch:
diff --git a/src/Http/Requests/MutateRequest.php b/src/Http/Requests/MutateRequest.php
index d17ff51..8acdca6 100644
--- a/src/Http/Requests/MutateRequest.php
+++ b/src/Http/Requests/MutateRequest.php
@@ -17,6 +17,7 @@ class MutateRequest extends RestRequest
     public function rules()
     {
         return [
+            'mutate'   => ['required'],
             'mutate.*' => new MutateRules(
                 $this->route()->controller::newResource(),
                 $this,


Test patch:
diff --git a/tests/Feature/Controllers/MutateCreateOperationsTest.php b/tests/Feature/Controllers/MutateCreateOperationsTest.php
index 601ed8b..3952dc3 100644
--- a/tests/Feature/Controllers/MutateCreateOperationsTest.php
+++ b/tests/Feature/Controllers/MutateCreateOperationsTest.php
@@ -41,6 +41,20 @@ class MutateCreateOperationsTest extends TestCase
         $response->assertJsonStructure(['message', 'errors' => ['mutate.0.attributes']]);
     }
 
+    public function test_creating_a_resource_using_no_mutate_key(): void
+    {
+        Gate::policy(Model::class, GreenPolicy::class);
+
+        $response = $this->post(
+            '/api/models/mutate',
+            [],
+            ['Accept' => 'application/json']
+        );
+
+        $response->assertStatus(422);
+        $response->assertJsonStructure(['message', 'errors' => ['mutate']]);
+    }
+
     public function test_creating_a_resource_using_not_authorized_attach_root_operator(): void
     {
         Gate::policy(Model::class, GreenPolicy::class);