Throw ApiException for requests with the user's token too

Requests with the user's token threw a bare ResourceException with a
message like "… for resource [Anikeen\Id\Resources\Order]" and no
error code, while app requests threw ApiException. Both throw
ApiException now: status (also getCode()), Anikeen ID's error code and
message, isNotFound(), isConflict(), isTemporary(). Failed lists throw
CollectionException, now a subclass of ApiException. A request without
a response (connection refused, timeout) throws ApiException with
status 0 instead of a Guzzle exception.

ApiException extends ResourceException, so existing catch blocks keep
working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Maurice PreußandClaude Opus 5.5 committed 2026-11-04 18:28:50 +01:00
1 parent a4345e72ec
commit 57ce0b4a79
8 files changed
+196 -33

No files matched your search

+25
View File
@@ -2,6 +2,7 @@
namespace Anikeen\Id\Exceptions;
use Anikeen\Id\Result;
use Throwable;
/**
@@ -19,6 +20,30 @@ class ApiException extends ResourceException
parent::__construct($message, $status, $previous);
}
/**
* The exception for a failed request: Anikeen ID's message and error code, the HTTP status
* (0 when there was no response).
*/
public static function fromResult(Result $result): static
{
$body = is_object($result->data) ? $result->data : null;
return new static(
rtrim((string) ($body->message ?? $result->error()), '.'),
$result->response()?->getStatusCode() ?? 0,
$body->error ?? null,
$result->exception,
);
}
/**
* The exception for a request that got no response (network error, timeout).
*/
public static function unreachable(Throwable $previous): static
{
return new static(sprintf('Anikeen ID is not reachable: %s', $previous->getMessage()), 0, null, $previous);
}
public function isNotFound(): bool
{
return $this->status === 404;
+6 -6
View File
@@ -2,10 +2,10 @@
namespace Anikeen\Id\Exceptions;
use Anikeen\Id\Result;
use Exception;
class CollectionException extends Exception
/**
* A list request failed. Like ApiException it carries the HTTP status (also as getCode()) and
* Anikeen ID's error code.
*/
class CollectionException extends ApiException
{
}
}
+8 -2
View File
@@ -7,6 +7,7 @@ use Anikeen\Id\Exceptions\CollectionException;
use Anikeen\Id\Helpers\Paginator;
use Anikeen\Id\Result;
use Closure;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Response;
use JsonSerializable;
use Throwable;
@@ -34,10 +35,15 @@ abstract class BaseCollection implements JsonSerializable
*/
protected function __construct(callable $callable)
{
$this->result = $callable();
try {
$this->result = $callable();
} catch (GuzzleException $e) {
// no response at all (connection refused, timeout)
throw CollectionException::unreachable($e);
}
if (!$this->result->success()) {
throw new CollectionException(sprintf('%s for collection [%s]', rtrim($this->result->data->message, '.'), get_called_class()), $this->result->response->getStatusCode());
throw CollectionException::fromResult($this->result);
}
}
+11 -4
View File
@@ -2,9 +2,10 @@
namespace Anikeen\Id\Resources;
use Anikeen\Id\Exceptions\ApiException;
use Anikeen\Id\Exceptions\ConfirmationRequiredException;
use Anikeen\Id\Exceptions\ResourceException;
use Anikeen\Id\Result;
use GuzzleHttp\Exception\GuzzleException;
use JsonSerializable;
#[\AllowDynamicProperties]
@@ -13,11 +14,17 @@ abstract class BaseResource implements JsonSerializable
public Result $result;
/**
* @throws ResourceException
* @throws ApiException the request failed (status, error code; a ResourceException)
* @throws ConfirmationRequiredException the user has to confirm it on Anikeen ID
*/
public function __construct(callable $callable)
{
$this->result = $callable();
try {
$this->result = $callable();
} catch (GuzzleException $e) {
// no response at all (connection refused, timeout)
throw ApiException::unreachable($e);
}
if (!$this->result->success()) {
if (($this->result->data->error ?? null) === 'confirmation_required') {
@@ -28,7 +35,7 @@ abstract class BaseResource implements JsonSerializable
);
}
throw new ResourceException(sprintf('%s for resource [%s]', rtrim($this->result->data->message, '.'), get_called_class()), $this->result->response->getStatusCode());
throw ApiException::fromResult($this->result);
}
foreach ($this->result->data as $key => $value) {