Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle HTTP exceptions in HttpTransport #254

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 4 additions & 122 deletions src/OpenSearch/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,6 @@

namespace OpenSearch;

use OpenSearch\Common\Exceptions\BadRequest400Exception;
use OpenSearch\Common\Exceptions\Conflict409Exception;
use OpenSearch\Common\Exceptions\Forbidden403Exception;
use OpenSearch\Common\Exceptions\Missing404Exception;
use OpenSearch\Common\Exceptions\NoDocumentsToGetException;
use OpenSearch\Common\Exceptions\NoShardAvailableException;
use OpenSearch\Common\Exceptions\RequestTimeout408Exception;
use OpenSearch\Common\Exceptions\RoutingMissingException;
use OpenSearch\Common\Exceptions\ScriptLangNotSupportedException;
use OpenSearch\Common\Exceptions\ServerErrorResponseException;
use OpenSearch\Common\Exceptions\Unauthorized401Exception;
use OpenSearch\Endpoints\AbstractEndpoint;
use OpenSearch\Namespaces\BooleanRequestWrapper;
use OpenSearch\Namespaces\NamespaceBuilderInterface;
Expand Down Expand Up @@ -106,11 +95,6 @@ class Client
*/
protected $registeredNamespaces = [];

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
private bool $throwExceptions = false;

/**
* @var AsyncSearchNamespace
*/
Expand Down Expand Up @@ -284,13 +268,11 @@ class Client
* @param TransportInterface|Transport $transport
* @param callable|EndpointFactoryInterface $endpointFactory
* @param NamespaceBuilderInterface[] $registeredNamespaces
* @param bool $throwExceptions
*/
public function __construct(
TransportInterface|Transport $transport,
callable|EndpointFactoryInterface $endpointFactory,
array $registeredNamespaces,
bool $throwExceptions = false,
) {
if (!$transport instanceof TransportInterface) {
@trigger_error('Passing an instance of \OpenSearch\Transport to ' . __METHOD__ . '() is deprecated in 2.3.2 and will be removed in 3.0.0. Pass an instance of \OpenSearch\TransportInterface instead.', E_USER_DEPRECATED);
Expand All @@ -311,13 +293,6 @@ public function __construct(
}
$this->endpoints = $endpoints;
$this->endpointFactory = $endpointFactory;
if ($throwExceptions === true) {
@trigger_error(
'The $throwExceptions parameter is deprecated in 2.4.0 and will be removed in 3.0.0. Check the response \'status_code\' instead',
E_USER_DEPRECATED
);
$this->throwExceptions = true;
}
$this->asyncSearch = new AsyncSearchNamespace($transport, $this->endpointFactory);
$this->asynchronousSearch = new AsynchronousSearchNamespace($transport, $this->endpointFactory);
$this->cat = new CatNamespace($transport, $this->endpointFactory);
Expand Down Expand Up @@ -2098,7 +2073,7 @@ public function extractArgument(array &$params, string $arg)
* Send a raw request to the cluster.
*
* @throws \Psr\Http\Client\ClientExceptionInterface
* @throws \OpenSearch\Common\Exceptions\OpenSearchException
* @throws \OpenSearch\Exception\HttpExceptionInterface
*/
public function request(
string $method,
Expand All @@ -2109,117 +2084,24 @@ public function request(
$body = $attributes['body'] ?? null;
$options = $attributes['options'] ?? [];

$response = $this->httpTransport->sendRequest($method, $uri, $params, $body, $options['headers'] ?? []);

// @todo: Remove this in the next major release.
// Throw legacy exceptions.
if ($this->throwExceptions) {
if (isset($response['status']) && $response['status'] >= 400) {
$this->throwLegacyException($response);
}
}

return $response;
return $this->httpTransport->sendRequest($method, $uri, $params, $body, $options['headers'] ?? []);
}

/**
* Send a request for an endpoint.
*
* @throws \Psr\Http\Client\ClientExceptionInterface
* @throws \OpenSearch\Common\Exceptions\OpenSearchException
* @throws \OpenSearch\Exception\HttpExceptionInterface
*/
private function performRequest(AbstractEndpoint $endpoint): array|string|null
{
$response = $this->httpTransport->sendRequest(
return $this->httpTransport->sendRequest(
$endpoint->getMethod(),
$endpoint->getURI(),
$endpoint->getParams(),
$endpoint->getBody(),
$endpoint->getOptions()
);

// @todo: Remove this in the next major release.
// Throw legacy exceptions.
if ($this->throwExceptions) {
if (isset($response['status']) && $response['status'] >= 400) {
$this->throwLegacyException($response);
}
}

return $response;
}

/**
* Throw legacy exceptions.
*
* @param array<string,mixed> $response
*
* @throws \OpenSearch\Common\Exceptions\OpenSearchException
*/
private function throwLegacyException(array $response): void
{
if ($response['status'] >= 400 && $response['status'] < 500) {
$this->throwLegacyClientException($response);
}
if ($response['status'] >= 500) {
$this->throwLegacyServerException($response);
}
}

/**
* Throw legacy client exceptions based on status code.
*
* @throws \OpenSearch\Common\Exceptions\OpenSearchException
*/
private function throwLegacyClientException($response): void
{
$statusCode = $response['status_code'];
$responseBody = $this->convertBodyToString($response['body'], $statusCode);
throw match ($statusCode) {
401 => new Unauthorized401Exception($responseBody, $statusCode),
403 => new Forbidden403Exception($responseBody, $statusCode),
404 => new Missing404Exception($responseBody, $statusCode),
409 => new Conflict409Exception($responseBody, $statusCode),
400 => (str_contains($responseBody, 'script_lang not supported'))
? new ScriptLangNotSupportedException($responseBody . $statusCode)
: new BadRequest400Exception($responseBody, $statusCode),
408 => new RequestTimeout408Exception($responseBody, $statusCode),
default => new BadRequest400Exception($responseBody, $statusCode),
};
}

/**
* Throw legacy server exceptions based on status code.
*
* @throws \OpenSearch\Common\Exceptions\OpenSearchException
*/
private function throwLegacyServerException($response): void
{
$statusCode = $response['status_code'];
$error = $response['body']['error'] ?? [];
$reason = $error['reason'] ?? 'undefined reason';
$type = $error['type'] ?? 'undefined type';
$errorMessage = "$type: $reason";
$responseBody = $this->convertBodyToString($response['body'], $statusCode);

$exception = new ServerErrorResponseException($responseBody, $statusCode);
if ($statusCode === 500) {
if (str_contains($responseBody, "RoutingMissingException")) {
$exception = new RoutingMissingException($errorMessage, $statusCode);
} elseif (preg_match('/ActionRequestValidationException.+ no documents to get/', $responseBody) === 1) {
$exception = new NoDocumentsToGetException($errorMessage, $statusCode);
} elseif (str_contains($responseBody, 'NoShardAvailableActionException')) {
$exception = new NoShardAvailableException($errorMessage, $statusCode);
}
}
throw $exception;
}

private function convertBodyToString(mixed $body, int $statusCode): string
{
return empty($body)
? "Unknown $statusCode error from OpenSearch"
: (is_string($body) ? $body : json_encode($body));
}

}
8 changes: 6 additions & 2 deletions src/OpenSearch/Common/Exceptions/Forbidden403Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(Forbidden403Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
use OpenSearch\Exception\ForbiddenHttpException;

@trigger_error(Forbidden403Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\ForbiddenHttpException instead', E_USER_DEPRECATED);

Check warning on line 26 in src/OpenSearch/Common/Exceptions/Forbidden403Exception.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/Forbidden403Exception.php#L26

Added line #L26 was not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*
* @see \OpenSearch\Exception\ForbiddenHttpException
*/
class Forbidden403Exception extends \Exception implements OpenSearchException
class Forbidden403Exception extends ForbiddenHttpException
{
}
11 changes: 9 additions & 2 deletions src/OpenSearch/Common/Exceptions/Missing404Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(Missing404Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
use OpenSearch\Exception\NotFoundHttpException;

@trigger_error(
Missing404Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NotFoundHttpException instead.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*
* @see \OpenSearch\Exception\NotFoundHttpException
*/
class Missing404Exception extends \Exception implements OpenSearchException
class Missing404Exception extends NotFoundHttpException
{
}
11 changes: 8 additions & 3 deletions src/OpenSearch/Common/Exceptions/NoDocumentsToGetException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(NoDocumentsToGetException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);
@trigger_error(
NoDocumentsToGetException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoDocumentsToGetException instead.',
E_USER_DEPRECATED
);

Check warning on line 27 in src/OpenSearch/Common/Exceptions/NoDocumentsToGetException.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/NoDocumentsToGetException.php#L24-L27

Added lines #L24 - L27 were not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoDocumentsToGetException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class NoDocumentsToGetException extends ServerErrorResponseException implements OpenSearchException
class NoDocumentsToGetException extends \OpenSearch\Exception\NoDocumentsToGetException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(
NoNodesAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
class NoNodesAvailableException extends ServerErrorResponseException implements OpenSearchException
{
}
12 changes: 11 additions & 1 deletion src/OpenSearch/Common/Exceptions/NoShardAvailableException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class NoShardAvailableException extends ServerErrorResponseException implements OpenSearchException
@trigger_error(
NoShardAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoShardAvailableException instead.',
E_USER_DEPRECATED
);

Check warning on line 27 in src/OpenSearch/Common/Exceptions/NoShardAvailableException.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/NoShardAvailableException.php#L24-L27

Added lines #L24 - L27 were not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\NoShardAvailableException instead.
*
* @see \OpenSearch\Exception\NoShardAvailableException
*/
class NoShardAvailableException extends \OpenSearch\Exception\NoShardAvailableException
{
}
12 changes: 10 additions & 2 deletions src/OpenSearch/Common/Exceptions/OpenSearchException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@

namespace OpenSearch\Common\Exceptions;

use Throwable;
use OpenSearch\Exception\OpenSearchExceptionInterface;

interface OpenSearchException extends Throwable
@trigger_error(
NoNodesAvailableException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.',
E_USER_DEPRECATED
);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
interface OpenSearchException extends OpenSearchExceptionInterface
{
}
12 changes: 11 additions & 1 deletion src/OpenSearch/Common/Exceptions/RoutingMissingException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class RoutingMissingException extends ServerErrorResponseException implements OpenSearchException
@trigger_error(
RoutingMissingException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use \OpenSearch\Exception\RoutingMissingException instead.',
E_USER_DEPRECATED
);

Check warning on line 27 in src/OpenSearch/Common/Exceptions/RoutingMissingException.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/RoutingMissingException.php#L24-L27

Added lines #L24 - L27 were not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class RoutingMissingException extends \OpenSearch\Exception\RoutingMissingException
{
}
4 changes: 3 additions & 1 deletion src/OpenSearch/Common/Exceptions/RuntimeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

namespace OpenSearch\Common\Exceptions;

class RuntimeException extends \RuntimeException implements OpenSearchException
use OpenSearch\Exception\OpenSearchExceptionInterface;

class RuntimeException extends \RuntimeException implements OpenSearchExceptionInterface
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@

namespace OpenSearch\Common\Exceptions;

class ScriptLangNotSupportedException extends BadRequest400Exception implements OpenSearchException
@trigger_error(
ScriptLangNotSupportedException::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\ScriptLangNotSupportedException instead.',
E_USER_DEPRECATED
);

Check warning on line 27 in src/OpenSearch/Common/Exceptions/ScriptLangNotSupportedException.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/ScriptLangNotSupportedException.php#L24-L27

Added lines #L24 - L27 were not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\ScriptLangNotSupportedException
*/
class ScriptLangNotSupportedException extends \OpenSearch\Exception\ScriptLangNotSupportedException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

namespace OpenSearch\Common\Exceptions;

@trigger_error(RequestTimeout408Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0.', E_USER_DEPRECATED);

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0.
*/
class ServerErrorResponseException extends TransportException implements OpenSearchException
{
}
14 changes: 13 additions & 1 deletion src/OpenSearch/Common/Exceptions/Unauthorized401Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@

namespace OpenSearch\Common\Exceptions;

class Unauthorized401Exception extends \Exception implements OpenSearchException
use OpenSearch\Exception\UnauthorizedHttpException;

@trigger_error(
Unauthorized401Exception::class . ' is deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.',
E_USER_DEPRECATED
);

Check warning on line 29 in src/OpenSearch/Common/Exceptions/Unauthorized401Exception.php

View check run for this annotation

Codecov / codecov/patch

src/OpenSearch/Common/Exceptions/Unauthorized401Exception.php#L26-L29

Added lines #L26 - L29 were not covered by tests

/**
* @deprecated in 2.3.2 and will be removed in 3.0.0. Use OpenSearch\Exception\UnauthorizedHttpException instead.
*
* @see \OpenSearch\Exception\UnauthorizedHttpException
*/
class Unauthorized401Exception extends UnauthorizedHttpException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

namespace OpenSearch\Common\Exceptions;

class UnexpectedValueException extends \UnexpectedValueException implements OpenSearchException
use OpenSearch\Exception\OpenSearchExceptionInterface;

class UnexpectedValueException extends \UnexpectedValueException implements OpenSearchExceptionInterface
{
}
Loading
Loading