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

+22 -8
View File
@@ -417,23 +417,37 @@ object through the API when the current state matters. The admin panel can send
### Errors
Calls with the user's token throw `Anikeen\Id\Exceptions\ResourceException` when Anikeen ID
rejects them; `getCode()` is the HTTP status (e.g. `422` for invalid data, `404` for an unknown
ID) and `getMessage()` the reason. App calls (`app*()`) throw its subclass `ApiException`, which
adds a stable `error` code. Catching `ResourceException` covers both:
Every failed request throws `Anikeen\Id\Exceptions\ApiException`, with the user's token as
well as with the app's (`app*()`). It carries:
- `status`: the HTTP status (also `getCode()`), `0` when Anikeen ID could not be reached,
- `error`: a stable error code when Anikeen ID sent one (e.g. `billing_address_missing`,
`already_cancelled`), otherwise `null`,
- `getMessage()`: Anikeen ID's reason,
- `isNotFound()` (404), `isConflict()` (409) and `isTemporary()` (no response, 429 or 5xx: retry
later).
```php
use Anikeen\Id\Exceptions\ResourceException;
use Anikeen\Id\Exceptions\ApiException;
try {
$order = $user->orders()->create($attributes);
} catch (ResourceException $e) {
} catch (ApiException $e) {
if ($e->isTemporary()) {
return back()->with('error', 'Anikeen ID is not reachable right now, please try again.');
}
report($e);
return back()->with('error', 'The order could not be created.');
return back()->with('error', $e->getMessage());
}
```
Failed lists (`$user->invoices()`, …) throw `CollectionException`, a subclass of `ApiException`.
`ConfirmationRequiredException` (a third-party app called `checkout()`, see above) stays its own
type. All of them extend `ResourceException`, so existing `catch (ResourceException $e)` blocks
keep working.
### Testing
Develop against staging (`ANIKEEN_ID_MODE=staging`) with an OAuth client registered there.
@@ -700,7 +714,7 @@ $user = $result->shift(); // the object, or the first item of a list
```
Resource methods (`$user->orders()`, `$anikeenId->sshKeysByUserId()`, …) return objects and throw
`ResourceException` instead (see [Errors](#errors)).
`ApiException` instead (see [Errors](#errors)).
## Examples