From cb481f8c47dc3b4862b0f9c7f8df0e1905267a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Richiardi?= <142845401+KroderDev@users.noreply.github.com> Date: Wed, 13 Aug 2025 18:17:25 -0400 Subject: [PATCH] Check API responses before model success --- src/Models/Model.php | 100 +++++++++++++++++++++++++++++++-- tests/Models/ApiModelTest.php | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 6 deletions(-) diff --git a/src/Models/Model.php b/src/Models/Model.php index c62d8ca..a9fcfb6 100644 --- a/src/Models/Model.php +++ b/src/Models/Model.php @@ -139,8 +139,22 @@ public static function updateById($id, array $attributes): bool $method = strtolower(config('microservice.models.update_method', 'put')); $response = static::client()->{$method}(static::endpoint().'/'.$id, $attributes); - if (is_object($response) && method_exists($response, 'successful')) { - return $response->successful(); + if (is_object($response)) { + if (method_exists($response, 'successful')) { + return $response->successful(); + } + + if (method_exists($response, 'status')) { + $status = $response->status(); + + return $status >= 200 && $status < 300; + } + + if (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + + return $status >= 200 && $status < 300; + } } return true; @@ -160,6 +174,28 @@ public function update(array $attributes = [], array $options = []): bool $method = strtolower(config('microservice.models.update_method', 'put')); $response = static::client()->{$method}(static::endpoint().'/'.$this->getKey(), $this->attributesToArray()); + if (is_object($response)) { + if (method_exists($response, 'successful') && ! $response->successful()) { + return false; + } + + if (method_exists($response, 'status')) { + $status = $response->status(); + + if ($status < 200 || $status >= 300) { + return false; + } + } + + if (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + + if ($status < 200 || $status >= 300) { + return false; + } + } + } + $data = static::parseResponse($response); if ($fresh = static::fromResponse($data)) { $this->fill($fresh->attributesToArray()); @@ -182,9 +218,26 @@ public function updateOrFail(array $attributes = [], array $options = []): bool $method = strtolower(config('microservice.models.update_method', 'put')); $response = static::client()->{$method}(static::endpoint().'/'.$this->getKey(), $this->attributesToArray()); + if (is_object($response)) { + if (method_exists($response, 'successful') && ! $response->successful()) { + throw new \RuntimeException('Update failed.'); + } - if (is_object($response) && method_exists($response, 'successful') && ! $response->successful()) { - throw new \RuntimeException('Update failed.'); + if (method_exists($response, 'status')) { + $status = $response->status(); + + if ($status < 200 || $status >= 300) { + throw new \RuntimeException('Update failed with status '.$status.'.'); + } + } + + if (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + + if ($status < 200 || $status >= 300) { + throw new \RuntimeException('Update failed with status '.$status.'.'); + } + } } $data = static::parseResponse($response); @@ -208,6 +261,28 @@ public function save(array $options = []): bool $response = static::client()->post(static::endpoint(), $this->attributesToArray()); } + if (is_object($response)) { + if (method_exists($response, 'successful') && ! $response->successful()) { + return false; + } + + if (method_exists($response, 'status')) { + $status = $response->status(); + + if ($status < 200 || $status >= 300) { + return false; + } + } + + if (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + + if ($status < 200 || $status >= 300) { + return false; + } + } + } + $data = static::parseResponse($response); if ($fresh = static::fromResponse($data)) { $this->fill($fresh->attributesToArray()); @@ -225,9 +300,22 @@ public function delete(): bool { $method = strtolower(config('microservice.models.delete_method', 'delete')); $response = static::client()->{$method}(static::endpoint().'/'.$this->getKey()); + if (is_object($response)) { + if (method_exists($response, 'successful')) { + return $response->successful(); + } + + if (method_exists($response, 'status')) { + $status = $response->status(); - if (is_object($response) && method_exists($response, 'successful')) { - return $response->successful(); + return $status >= 200 && $status < 300; + } + + if (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + + return $status >= 200 && $status < 300; + } } return true; diff --git a/tests/Models/ApiModelTest.php b/tests/Models/ApiModelTest.php index 0550c27..e529ed5 100644 --- a/tests/Models/ApiModelTest.php +++ b/tests/Models/ApiModelTest.php @@ -238,6 +238,30 @@ public function delete_users_respects_configured_method() ], $this->gateway->getCalls()); } + /** @test */ + public function delete_returns_false_on_failed_response() + { + $this->gateway = new class () extends FakeGatewayClient { + public function delete(string $uri) + { + parent::delete($uri); + + return new class () { + public function successful() + { + return false; + } + }; + } + }; + $this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway); + + $user = new RemoteUser(['id' => 6]); + $user->exists = true; + + $this->assertFalse($user->delete()); + } + /** @test */ public function static_update_users_gateway() { @@ -258,6 +282,34 @@ public function put(string $uri, array $data = []) ], $this->gateway->getCalls()); } + /** @test */ + public function static_update_returns_false_on_failed_response() + { + $this->gateway = new class () extends FakeGatewayClient { + public function put(string $uri, array $data = []) + { + parent::put($uri, $data); + + return new class () { + public function successful() + { + return false; + } + + public function json() + { + return []; + } + }; + } + }; + $this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway); + + $result = RemoteUser::updateById(10, ['name' => 'Bad']); + + $this->assertFalse($result); + } + /** @test */ public function instance_update_users_gateway() { @@ -271,6 +323,56 @@ public function instance_update_users_gateway() ], $this->gateway->getCalls()); } + /** @test */ + public function update_returns_false_on_failed_response() + { + $this->gateway = new class () extends FakeGatewayClient { + public function put(string $uri, array $data = []) + { + parent::put($uri, $data); + + return new class () { + public function successful() + { + return false; + } + + public function json() + { + return []; + } + }; + } + }; + $this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway); + + $user = new RemoteUser(['id' => 12, 'name' => 'Old']); + $user->exists = true; + + $this->assertFalse($user->update(['name' => 'Fail'])); + } + + /** @test */ + public function update_propagates_api_gateway_exceptions() + { + $this->gateway = new class () extends FakeGatewayClient { + public function put(string $uri, array $data = []) + { + parent::put($uri, $data); + + throw new \Kroderdev\LaravelMicroserviceCore\Exceptions\ApiGatewayException(500); + } + }; + $this->app->bind(ApiGatewayClientInterface::class, fn () => $this->gateway); + + $user = new RemoteUser(['id' => 15, 'name' => 'Old']); + $user->exists = true; + + $this->expectException(\Kroderdev\LaravelMicroserviceCore\Exceptions\ApiGatewayException::class); + + $user->update(['name' => 'Boom']); + } + /** @test */ public function find_or_fail_throws_when_not_found() {