Fehler
Jeder Fehlschlag wirft eine Exception. Eine Klasse für eine Ablehnung, eine für eine ausbleibende Antwort und eine request id bei jedem API-Fehler.
Einen Fehler abfangen
use OpenEmail\Exception\ApiException;use OpenEmail\Exception\NetworkException; $message = [ 'from' => '[email protected]', 'to' => '[email protected]', 'subject' => 'Your September invoice', 'text' => 'Invoice attached.',]; try { $client->emails->send($message);} catch (ApiException $error) { if ($error->isValidation()) { error_log($error->errorCode . ' ' . $error->param . ' ' . $error->getMessage()); } if ($error->isPermission()) { $book = $client->addresses->listAll(); error_log('this key may send as ' . implode(', ', array_column($book->addresses, 'address'))); } if ($error->isRateLimited()) { error_log('try again in ' . $error->retryAfterSeconds . ' seconds'); } error_log($error->status . ' ' . $error->requestId); throw $error;} catch (NetworkException $error) { if ($error->isTimeout()) { error_log('no answer in time'); } throw $error;}Ein permission_error bei einem Versand liegt meist am Sende-Scope des SCHLÜSSELS, an einer Domain oder einer Adresse, die ihm nicht zugestanden wurde, und nicht am Workspace. Darum protokolliert das Beispiel, was addresses->listAll() als zulässige Absenderadressen dieses Schlüssels nennt.
Jede Art von Ablehnung hat eine eigene Unterklasse, ein catch kann also anhand der Klasse auswählen, welche es behandelt, und den Rest nach oben durchlassen.
use OpenEmail\Exception\AuthenticationException;use OpenEmail\Exception\OpenEmailException;use OpenEmail\Exception\PermissionException;use OpenEmail\Exception\ValidationException; $message = [ 'from' => '[email protected]', 'to' => '[email protected]', 'subject' => 'Your September invoice', 'text' => 'Invoice attached.',]; try { $client->emails->send($message);} catch (ValidationException $error) { error_log($error->param . ': ' . $error->getMessage());} catch (AuthenticationException|PermissionException $error) { error_log('the key cannot do this: ' . $error->errorCode); throw $error;} catch (OpenEmailException $error) { error_log($error::class . ': ' . $error->getMessage()); throw $error;}Die Klassen
Jede Klasse liegt in OpenEmail\Exception.
| Klasse | Wann |
|---|---|
| OpenEmailException | Das Interface, das jede Exception implementiert, die das Paket wirft, catch (OpenEmailException $error) fängt also alle ab, InvalidArgumentException eingeschlossen. |
| ApiException | Die API hat geantwortet, und zwar nicht mit einem Erfolg. Trägt status, type, errorCode, param, docUrl, requestId, retryAfterSeconds, fields und body. Wird als diese Klasse selbst geworfen, wenn type gleich api_error ist, wie bei einem Serverfehler, und sonst als die Unterklasse für seinen type. Sie erweitert RuntimeException. |
| InvalidRequestException, AuthenticationException, PermissionException, NotFoundException, ConflictException, ValidationException und RateLimitException | Unterklassen von ApiException, eine für jeden type: invalid_request_error, authentication_error, permission_error, not_found_error, conflict_error, validation_error und rate_limit_error. |
| NetworkException | Es kam keine Antwort an: DNS, TLS, eine abgelehnte oder abgebrochene Verbindung oder das Timeout. getPrevious() enthält die zugrunde liegende Exception, und isTimeout() ist true, wenn das Timeout der Grund war. Sie erweitert RuntimeException. |
| WebhookSignatureException | OpenEmail::verifyWebhookSignature() hat eine Zustellung abgelehnt. Sie erweitert UnexpectedValueException. |
| InvalidArgumentException | Wird geworfen, bevor etwas gesendet wird: ein fehlender oder fehlerhafter Schlüssel, eine unbrauchbare baseUrl:, eine leere id. Sie erweitert PHPs eigene InvalidArgumentException, weil sie bedeutet, dass der Aufruf selbst falsch ist. |
Was eine ApiException trägt
getMessage()string- Der eigene Satz der API, für Menschen geschrieben, der den beanstandeten Wert nennt, sofern es einen gibt. Kein stabiler Bezeichner, verzweigen Sie also über `errorCode`.
statusint or null- Der HTTP-Status der Antwort, den auch `getCode()` zurückgibt. Nur dann null, wenn ein Erfolg in einer Form zurückkam, die der Client nicht lesen konnte.
typestring- Einer der acht Werte in `OpenEmail\Constants\ErrorTypes`, einer festen Menge, die nicht wachsen wird. Nennt der Body keinen, wird er aus dem Status abgeleitet.
errorCodestring- Der konkrete Fehlschlag, etwa `from_address_forbidden` oder `invalid_email_address`. Er heißt `errorCode`, weil PHP `code` für die Zahl reserviert, die `getCode()` zurückgibt. Offen und erweiterbar, behandeln Sie einen unbekannten daher als seinen `type`. Er ist `unrecognised_response`, wenn der Body nicht der Fehlerumschlag der API war.
paramstring or null- Das abgelehnte Feld als Pfad mit Punkten, etwa `to.0`, wenn der Fehlschlag eines nennt.
docUrlstring or null- Eine Seite zu diesem Fehlschlag, wenn die API eine nennt.
requestIdstring or null- Die id, unter der der Server die Anfrage protokolliert hat, aus dem Body oder dem Header `x-request-id`.
retryAfterSecondsint, float or null- Die Wartezeit, die der Server in `Retry-After` verlangt hat, in Sekunden, ob er nun eine Zahl oder ein Datum gesendet hat. null, wenn er keine gesendet hat.
fieldsarray or null- Ein Array pro Problem, jeweils mit `key` und `error`, etwa `['key' => 'email', 'error' => 'email']`, wenn `forms->subscribe` die Antworten mit einem 422 `invalid_form_submission` abgelehnt hat. null, wenn der Fehler keine auflistet.
bodymixed- Die gesamte Fehlerantwort, dekodiert. null, wenn sie leer oder kein JSON war.
| Methode | True, wenn |
|---|---|
| isAuth() | type ist authentication_error, ein 401: kein Schlüssel, die falsche Art von Zugangsdaten oder ein Schlüssel, den wir nicht ausgestellt haben. |
| isPermission() | permission_error, ein 403: ein echter Schlüssel ohne den Scope oder die From-Adresse, die er braucht. |
| isScopeMissing() | errorCode ist insufficient_scope, der 403, der einen fehlenden Scope nennt. |
| isInvalidRequest() | invalid_request_error, ein 400: eine Anfrage, die nicht verstanden werden konnte. Eine Nachricht über der Größenobergrenze kommt als 422 message_too_large zurück, isValidation() ist daher die Methode, die sie abfängt. |
| isValidation() | validation_error, ein 422: Das Schema hat sie abgelehnt, und param nennt das Feld. |
| isNotFound() | not_found_error, ein 404: keine solche Ressource. |
| isConflict() | conflict_error, ein 409: Die Ressource ist über den Punkt hinaus, an dem dies mit ihr möglich wäre. |
| isRateLimited() | rate_limit_error, ein 429. retryAfterSeconds enthält die Wartezeit, wenn der Server eine genannt hat. |
| isServerError() | status ist 500 oder höher. Nennen Sie requestId, wenn Sie den Support kontaktieren. |
| isRetryable() | status ist 408, 429, 500, 502, 503 oder 504. |
| isStepUpRequired() | errorCode ist step_up_required, der 403, den ein OAuth-Zugriffstoken vor einer heiklen Änderung bekommt, bis die Person einen Code bestätigt hat. |
Die meisten davon lesen type, die feste Hälfte des Umschlags, und jede Unterklasse steht für einen type. errorCode bleibt ein String, weil die API garantiert, dass er offen und erweiterbar ist, behandeln Sie einen unbekannten daher als seinen type. Eine geschlossene Liste würde ein Paket-Upgrade zum Preis dafür machen, eine neue Fehlerart lesen zu können.
Ein Body, der nicht dem Fehlerumschlag der API entspricht, wirft trotzdem eine ApiException, wobei type aus dem Status abgeleitet und errorCode auf unrecognised_response gesetzt wird. Ein Erfolg, dessen Body kein JSON ist, wirft ebenfalls eine.
isRetryable() beschreibt den Status, nicht Ihren Aufruf. Ein Aufruf, der gefahrlos wiederholt werden kann, wurde bereits wiederholt, wenn er die Exception wirft, und ein 429 wie send_quota_exceeded oder ai_quota_exceeded scheitert auf dieselbe Weise, bis sein Kontingent zurückgesetzt wird. Zeigen Sie ihn also einer Person, statt ihn in einer Schleife zu wiederholen.
Eine Exception, die Ihr HTTP-Client wirft, wird zu einer NetworkException, sobald alle Wiederholungen, die der Aufruf erlaubt, verbraucht sind, mit dem Original als getPrevious(). Eine LogicException und jeder Error, etwa ein TypeError, bedeuten einen Fehler im Client und werden daher unverändert geworfen und nie wiederholt. Psr18HttpClient behält von einer Exception des gekapselten Clients nur die Meldung, weil diese Exception die Anfrage samt ihrem Authorization-Header enthält.
requestId
Jede ApiException trägt die vom Server gesendete request id, aus dem Fehler-Body oder dem Header x-request-id, und sie ist das Einzige, was Ihren Fehlschlag mit einer Zeile im Serverlog verbindet. Ein Erfolg gibt allein den dekodierten Body zurück, an ihm gibt es daher keine request id zu lesen.