diff --git a/VERSION.md b/VERSION.md index ff3a77f..54ac1f5 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1,4 +1,7 @@ -4.5.0 +4.5.1 ## Added - Expose structured API error metadata on `FacturapiException`, including `code`, `path`, `location`, `errors`, `logId`, and response headers. + +## Fixed +- Return API error codes as strings, including legacy numeric codes. diff --git a/src/Exceptions/FacturapiException.php b/src/Exceptions/FacturapiException.php index 958dadd..ba47d15 100644 --- a/src/Exceptions/FacturapiException.php +++ b/src/Exceptions/FacturapiException.php @@ -48,9 +48,22 @@ public function getRawBody(): ?string return $this->rawBody; } - public function getErrorCode(): mixed + public function getErrorCode(): ?string { - return is_array($this->errorData) ? ($this->errorData['code'] ?? null) : null; + if (!is_array($this->errorData) || !array_key_exists('code', $this->errorData)) { + return null; + } + + $code = $this->errorData['code']; + if ($code === null) { + return null; + } + + if (is_string($code)) { + return $code; + } + + return is_int($code) || is_float($code) ? (string) $code : null; } public function getErrorPath(): ?string diff --git a/tests/Http/ErrorHandlingTest.php b/tests/Http/ErrorHandlingTest.php index d22e7d2..61df2e0 100644 --- a/tests/Http/ErrorHandlingTest.php +++ b/tests/Http/ErrorHandlingTest.php @@ -89,4 +89,20 @@ public function testNonJsonErrorsStillExposeRawBody(): void self::assertSame($rawBody, $exception->getRawBody()); } } + + public function testNumericApiErrorCodesAreConvertedToStrings(): void + { + $httpClient = new FakeHttpClient( + new Response(400, ['Content-Type' => 'application/json'], '{"code": 400}') + ); + + $invoices = new Invoices('sk_test_abc123', ['httpClient' => $httpClient]); + + try { + $invoices->create(['customer' => []]); + self::fail('Expected FacturapiException to be thrown.'); + } catch (FacturapiException $exception) { + self::assertSame('400', $exception->getErrorCode()); + } + } }