getStatusCode(); $rawBody = (string) $response->getBody(); $envelope = self::parseEnvelope($rawBody); if ($envelope === null) { $reason = $response->getReasonPhrase(); $message = sprintf( 'HTTP %d%s (no Connect error envelope)', $httpStatus, $reason !== '' ? ': ' . $reason : '', ); throw new ServiceUnavailableException( message: $message, connectCode: 'unavailable', httpStatus: $httpStatus, details: [], rawBody: $rawBody, ); } [$code, $message, $details] = $envelope; throw match ($code) { 'unauthenticated' => new AuthenticationException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), 'not_found' => new NotFoundException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), 'invalid_argument' => new InvalidArgumentException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), 'permission_denied' => new PermissionDeniedException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), 'resource_exhausted' => new RateLimitException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), 'unavailable' => new ServiceUnavailableException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), default => new OpenstatusException( message: $message, connectCode: $code, httpStatus: $httpStatus, details: $details, rawBody: $rawBody, ), }; } /** * @return array{0: string, 1: string, 2: list}|null */ private static function parseEnvelope(string $rawBody): ?array { if ($rawBody === '') { return null; } try { $decoded = json_decode($rawBody, associative: true, flags: JSON_THROW_ON_ERROR); } catch (\JsonException) { return null; } if (!is_array($decoded)) { return null; } $code = $decoded['code'] ?? null; $message = $decoded['message'] ?? null; if (!is_string($code) || !is_string($message)) { return null; } $details = self::parseDetails($decoded['details'] ?? null); return [$code, $message, $details]; } /** * @return list */ private static function parseDetails(mixed $raw): array { if (!is_array($raw)) { return []; } $details = []; foreach ($raw as $item) { if (!is_array($item)) { continue; } $type = $item['type'] ?? null; $value = $item['value'] ?? null; $debug = $item['debug'] ?? null; if (is_string($type) && is_string($value)) { $details[] = new ConnectErrorDetail( type: $type, value: $value, debug: is_string($debug) ? $debug : null, ); } } return $details; } }