Centralized prefix for problem detail types

This commit is contained in:
Alejandro Celaya
2022-08-14 13:12:10 +02:00
parent 2650cb89b5
commit a41835573b
16 changed files with 77 additions and 51 deletions

View File

@@ -6,12 +6,14 @@ use Laminas\Stratigility\Middleware\ErrorHandler;
use Mezzio\ProblemDetails\ProblemDetailsMiddleware; use Mezzio\ProblemDetails\ProblemDetailsMiddleware;
use Shlinkio\Shlink\Common\Logger; use Shlinkio\Shlink\Common\Logger;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
return [ return [
'problem-details' => [ 'problem-details' => [
'default_types_map' => [ 'default_types_map' => [
404 => 'NOT_FOUND', // TODO Define new values, with backwards compatibility if possible 404 => toProblemDetailsType('not-found'),
500 => 'INTERNAL_SERVER_ERROR', // TODO Define new values, with backwards compatibility if possible 500 => toProblemDetailsType('internal-server-error'),
], ],
], ],

View File

@@ -127,3 +127,8 @@ function camelCaseToHumanFriendly(string $value): string
return ucfirst($filter->filter($value)); return ucfirst($filter->filter($value));
} }
function toProblemDetailsType(string $errorCode): string
{
return sprintf('https://shlink.io/api/error/%s', $errorCode);
}

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier; use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class DeleteShortUrlException extends DomainException implements ProblemDetailsExceptionInterface class DeleteShortUrlException extends DomainException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Cannot delete short URL'; private const TITLE = 'Cannot delete short URL';
public const TYPE = 'https://shlink.io/api/error/invalid-short-url-deletion'; public const ERROR_CODE = 'invalid-short-url-deletion';
public static function fromVisitsThreshold(int $threshold, ShortUrlIdentifier $identifier): self public static function fromVisitsThreshold(int $threshold, ShortUrlIdentifier $identifier): self
{ {
@@ -32,7 +33,7 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY; $e->status = StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY;
$e->additional = [ $e->additional = [
'shortCode' => $shortCode, 'shortCode' => $shortCode,

View File

@@ -8,6 +8,7 @@ use Fig\Http\Message\StatusCodeInterface;
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait; use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class DomainNotFoundException extends DomainException implements ProblemDetailsExceptionInterface class DomainNotFoundException extends DomainException implements ProblemDetailsExceptionInterface
@@ -15,7 +16,7 @@ class DomainNotFoundException extends DomainException implements ProblemDetailsE
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Domain not found'; private const TITLE = 'Domain not found';
public const TYPE = 'https://shlink.io/api/error/domain-not-found'; public const ERROR_CODE = 'domain-not-found';
private function __construct(string $message, array $additional) private function __construct(string $message, array $additional)
{ {
@@ -23,7 +24,7 @@ class DomainNotFoundException extends DomainException implements ProblemDetailsE
$this->detail = $message; $this->detail = $message;
$this->title = self::TITLE; $this->title = self::TITLE;
$this->type = self::TYPE; $this->type = toProblemDetailsType(self::ERROR_CODE);
$this->status = StatusCodeInterface::STATUS_NOT_FOUND; $this->status = StatusCodeInterface::STATUS_NOT_FOUND;
$this->additional = $additional; $this->additional = $additional;
} }

View File

@@ -8,12 +8,14 @@ use Fig\Http\Message\StatusCodeInterface;
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait; use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
class ForbiddenTagOperationException extends DomainException implements ProblemDetailsExceptionInterface class ForbiddenTagOperationException extends DomainException implements ProblemDetailsExceptionInterface
{ {
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Forbidden tag operation'; private const TITLE = 'Forbidden tag operation';
public const TYPE = 'https://shlink.io/api/error/forbidden-tag-operation'; public const ERROR_CODE = 'forbidden-tag-operation';
public static function forDeletion(): self public static function forDeletion(): self
{ {
@@ -31,7 +33,7 @@ class ForbiddenTagOperationException extends DomainException implements ProblemD
$e->detail = $message; $e->detail = $message;
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_FORBIDDEN; $e->status = StatusCodeInterface::STATUS_FORBIDDEN;
return $e; return $e;

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use Throwable; use Throwable;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class InvalidUrlException extends DomainException implements ProblemDetailsExceptionInterface class InvalidUrlException extends DomainException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class InvalidUrlException extends DomainException implements ProblemDetailsExcep
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid URL'; private const TITLE = 'Invalid URL';
public const TYPE = 'https://shlink.io/api/error/invalid-url'; public const ERROR_CODE = 'invalid-url';
public static function fromUrl(string $url, ?Throwable $previous = null): self public static function fromUrl(string $url, ?Throwable $previous = null): self
{ {
@@ -25,7 +26,7 @@ class InvalidUrlException extends DomainException implements ProblemDetailsExcep
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = $status; $e->status = $status;
$e->additional = ['url' => $url]; $e->additional = ['url' => $url];

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl; use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class NonUniqueSlugException extends InvalidArgumentException implements ProblemDetailsExceptionInterface class NonUniqueSlugException extends InvalidArgumentException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid custom slug'; private const TITLE = 'Invalid custom slug';
public const TYPE = 'https://shlink.io/api/error/non-unique-slug'; public const ERROR_CODE = 'non-unique-slug';
public static function fromSlug(string $slug, ?string $domain = null): self public static function fromSlug(string $slug, ?string $domain = null): self
{ {
@@ -25,7 +26,7 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_BAD_REQUEST; $e->status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e->additional = ['customSlug' => $slug]; $e->additional = ['customSlug' => $slug];

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier; use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class ShortUrlNotFoundException extends DomainException implements ProblemDetailsExceptionInterface class ShortUrlNotFoundException extends DomainException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class ShortUrlNotFoundException extends DomainException implements ProblemDetail
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Short URL not found'; private const TITLE = 'Short URL not found';
public const TYPE = 'https://shlink.io/api/error/short-url-not-found'; public const ERROR_CODE = 'short-url-not-found';
public static function fromNotFound(ShortUrlIdentifier $identifier): self public static function fromNotFound(ShortUrlIdentifier $identifier): self
{ {
@@ -27,7 +28,7 @@ class ShortUrlNotFoundException extends DomainException implements ProblemDetail
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_NOT_FOUND; $e->status = StatusCodeInterface::STATUS_NOT_FOUND;
$e->additional = ['shortCode' => $shortCode]; $e->additional = ['shortCode' => $shortCode];

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use Shlinkio\Shlink\Core\Tag\Model\TagRenaming; use Shlinkio\Shlink\Core\Tag\Model\TagRenaming;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class TagConflictException extends RuntimeException implements ProblemDetailsExceptionInterface class TagConflictException extends RuntimeException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class TagConflictException extends RuntimeException implements ProblemDetailsExc
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Tag conflict'; private const TITLE = 'Tag conflict';
public const TYPE = 'https://shlink.io/api/error/tag-conflict'; public const ERROR_CODE = 'tag-conflict';
public static function forExistingTag(TagRenaming $renaming): self public static function forExistingTag(TagRenaming $renaming): self
{ {
@@ -24,7 +25,7 @@ class TagConflictException extends RuntimeException implements ProblemDetailsExc
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_CONFLICT; $e->status = StatusCodeInterface::STATUS_CONFLICT;
$e->additional = $renaming->toArray(); $e->additional = $renaming->toArray();

View File

@@ -8,6 +8,7 @@ use Fig\Http\Message\StatusCodeInterface;
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait; use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class TagNotFoundException extends DomainException implements ProblemDetailsExceptionInterface class TagNotFoundException extends DomainException implements ProblemDetailsExceptionInterface
@@ -15,7 +16,7 @@ class TagNotFoundException extends DomainException implements ProblemDetailsExce
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Tag not found'; private const TITLE = 'Tag not found';
public const TYPE = 'https://shlink.io/api/error/tag-not-found'; public const ERROR_CODE = 'tag-not-found';
public static function fromTag(string $tag): self public static function fromTag(string $tag): self
{ {
@@ -23,7 +24,7 @@ class TagNotFoundException extends DomainException implements ProblemDetailsExce
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_NOT_FOUND; $e->status = StatusCodeInterface::STATUS_NOT_FOUND;
$e->additional = ['tag' => $tag]; $e->additional = ['tag' => $tag];

View File

@@ -12,6 +12,7 @@ use Throwable;
use function array_keys; use function array_keys;
use function Shlinkio\Shlink\Core\arrayToString; use function Shlinkio\Shlink\Core\arrayToString;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
use const PHP_EOL; use const PHP_EOL;
@@ -21,7 +22,7 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid data'; private const TITLE = 'Invalid data';
public const TYPE = 'https://shlink.io/api/error/invalid-data'; public const ERROR_CODE = 'invalid-data';
private array $invalidElements; private array $invalidElements;
@@ -37,7 +38,7 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_BAD_REQUEST; $e->status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e->invalidElements = $invalidData; $e->invalidElements = $invalidData;
$e->additional = ['invalidElements' => array_keys($invalidData)]; $e->additional = ['invalidElements' => array_keys($invalidData)];

View File

@@ -15,6 +15,9 @@ use Shlinkio\Shlink\Core\Exception\TagConflictException;
use Shlinkio\Shlink\Core\Exception\TagNotFoundException; use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
use Shlinkio\Shlink\Core\Exception\ValidationException; use Shlinkio\Shlink\Core\Exception\ValidationException;
use function explode;
use function Functional\last;
/** @deprecated */ /** @deprecated */
class BackwardsCompatibleProblemDetailsException extends RuntimeException implements ProblemDetailsExceptionInterface class BackwardsCompatibleProblemDetailsException extends RuntimeException implements ProblemDetailsExceptionInterface
{ {
@@ -74,19 +77,20 @@ class BackwardsCompatibleProblemDetailsException extends RuntimeException implem
private function remapType(string $wrappedType): string private function remapType(string $wrappedType): string
{ {
return match ($wrappedType) { $lastSegment = last(explode('/', $wrappedType));
ValidationException::TYPE => 'INVALID_ARGUMENT', return match ($lastSegment) {
DeleteShortUrlException::TYPE => 'INVALID_SHORT_URL_DELETION', ValidationException::ERROR_CODE => 'INVALID_ARGUMENT',
DomainNotFoundException::TYPE => 'DOMAIN_NOT_FOUND', DeleteShortUrlException::ERROR_CODE => 'INVALID_SHORT_URL_DELETION',
ForbiddenTagOperationException::TYPE => 'FORBIDDEN_OPERATION', DomainNotFoundException::ERROR_CODE => 'DOMAIN_NOT_FOUND',
InvalidUrlException::TYPE => 'INVALID_URL', ForbiddenTagOperationException::ERROR_CODE => 'FORBIDDEN_OPERATION',
NonUniqueSlugException::TYPE => 'INVALID_SLUG', InvalidUrlException::ERROR_CODE => 'INVALID_URL',
ShortUrlNotFoundException::TYPE => 'INVALID_SHORTCODE', NonUniqueSlugException::ERROR_CODE => 'INVALID_SLUG',
TagConflictException::TYPE => 'TAG_CONFLICT', ShortUrlNotFoundException::ERROR_CODE => 'INVALID_SHORTCODE',
TagNotFoundException::TYPE => 'TAG_NOT_FOUND', TagConflictException::ERROR_CODE => 'TAG_CONFLICT',
MercureException::TYPE => 'MERCURE_NOT_CONFIGURED', TagNotFoundException::ERROR_CODE => 'TAG_NOT_FOUND',
MissingAuthenticationException::TYPE => 'INVALID_AUTHORIZATION', MercureException::ERROR_CODE => 'MERCURE_NOT_CONFIGURED',
VerifyAuthenticationException::TYPE => 'INVALID_API_KEY', MissingAuthenticationException::ERROR_CODE => 'INVALID_AUTHORIZATION',
VerifyAuthenticationException::ERROR_CODE => 'INVALID_API_KEY',
default => $wrappedType, default => $wrappedType,
}; };
} }

View File

@@ -8,12 +8,14 @@ use Fig\Http\Message\StatusCodeInterface;
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait; use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
class MercureException extends RuntimeException implements ProblemDetailsExceptionInterface class MercureException extends RuntimeException implements ProblemDetailsExceptionInterface
{ {
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Mercure integration not configured'; private const TITLE = 'Mercure integration not configured';
public const TYPE = 'https://shlink.io/api/error/mercure-not-configured'; public const ERROR_CODE = 'mercure-not-configured';
public static function mercureNotConfigured(): self public static function mercureNotConfigured(): self
{ {
@@ -21,7 +23,7 @@ class MercureException extends RuntimeException implements ProblemDetailsExcepti
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_NOT_IMPLEMENTED; $e->status = StatusCodeInterface::STATUS_NOT_IMPLEMENTED;
return $e; return $e;

View File

@@ -9,6 +9,7 @@ use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function implode; use function implode;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
use function sprintf; use function sprintf;
class MissingAuthenticationException extends RuntimeException implements ProblemDetailsExceptionInterface class MissingAuthenticationException extends RuntimeException implements ProblemDetailsExceptionInterface
@@ -16,7 +17,7 @@ class MissingAuthenticationException extends RuntimeException implements Problem
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid authorization'; private const TITLE = 'Invalid authorization';
public const TYPE = 'https://shlink.io/api/error/missing-authentication'; public const ERROR_CODE = 'missing-authentication';
public static function forHeaders(array $expectedHeaders): self public static function forHeaders(array $expectedHeaders): self
{ {
@@ -43,7 +44,7 @@ class MissingAuthenticationException extends RuntimeException implements Problem
$e->detail = $message; $e->detail = $message;
$e->title = self::TITLE; $e->title = self::TITLE;
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_UNAUTHORIZED; $e->status = StatusCodeInterface::STATUS_UNAUTHORIZED;
return $e; return $e;

View File

@@ -8,11 +8,13 @@ use Fig\Http\Message\StatusCodeInterface;
use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait; use Mezzio\ProblemDetails\Exception\CommonProblemDetailsExceptionTrait;
use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface; use Mezzio\ProblemDetails\Exception\ProblemDetailsExceptionInterface;
use function Shlinkio\Shlink\Core\toProblemDetailsType;
class VerifyAuthenticationException extends RuntimeException implements ProblemDetailsExceptionInterface class VerifyAuthenticationException extends RuntimeException implements ProblemDetailsExceptionInterface
{ {
use CommonProblemDetailsExceptionTrait; use CommonProblemDetailsExceptionTrait;
public const TYPE = 'https://shlink.io/api/error/invalid-api-key'; public const ERROR_CODE = 'invalid-api-key';
public static function forInvalidApiKey(): self public static function forInvalidApiKey(): self
{ {
@@ -20,7 +22,7 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
$e->detail = $e->getMessage(); $e->detail = $e->getMessage();
$e->title = 'Invalid API key'; $e->title = 'Invalid API key';
$e->type = self::TYPE; $e->type = toProblemDetailsType(self::ERROR_CODE);
$e->status = StatusCodeInterface::STATUS_UNAUTHORIZED; $e->status = StatusCodeInterface::STATUS_UNAUTHORIZED;
return $e; return $e;

View File

@@ -98,17 +98,17 @@ class BackwardsCompatibleProblemDetailsExceptionTest extends TestCase
{ {
yield ['foo', 'foo', true]; yield ['foo', 'foo', true];
yield ['bar', 'bar', true]; yield ['bar', 'bar', true];
yield [ValidationException::TYPE, 'INVALID_ARGUMENT']; yield [ValidationException::ERROR_CODE, 'INVALID_ARGUMENT'];
yield [DeleteShortUrlException::TYPE, 'INVALID_SHORT_URL_DELETION']; yield [DeleteShortUrlException::ERROR_CODE, 'INVALID_SHORT_URL_DELETION'];
yield [DomainNotFoundException::TYPE, 'DOMAIN_NOT_FOUND']; yield [DomainNotFoundException::ERROR_CODE, 'DOMAIN_NOT_FOUND'];
yield [ForbiddenTagOperationException::TYPE, 'FORBIDDEN_OPERATION']; yield [ForbiddenTagOperationException::ERROR_CODE, 'FORBIDDEN_OPERATION'];
yield [InvalidUrlException::TYPE, 'INVALID_URL']; yield [InvalidUrlException::ERROR_CODE, 'INVALID_URL'];
yield [NonUniqueSlugException::TYPE, 'INVALID_SLUG']; yield [NonUniqueSlugException::ERROR_CODE, 'INVALID_SLUG'];
yield [ShortUrlNotFoundException::TYPE, 'INVALID_SHORTCODE']; yield [ShortUrlNotFoundException::ERROR_CODE, 'INVALID_SHORTCODE'];
yield [TagConflictException::TYPE, 'TAG_CONFLICT']; yield [TagConflictException::ERROR_CODE, 'TAG_CONFLICT'];
yield [TagNotFoundException::TYPE, 'TAG_NOT_FOUND']; yield [TagNotFoundException::ERROR_CODE, 'TAG_NOT_FOUND'];
yield [MercureException::TYPE, 'MERCURE_NOT_CONFIGURED']; yield [MercureException::ERROR_CODE, 'MERCURE_NOT_CONFIGURED'];
yield [MissingAuthenticationException::TYPE, 'INVALID_AUTHORIZATION']; yield [MissingAuthenticationException::ERROR_CODE, 'INVALID_AUTHORIZATION'];
yield [VerifyAuthenticationException::TYPE, 'INVALID_API_KEY']; yield [VerifyAuthenticationException::ERROR_CODE, 'INVALID_API_KEY'];
} }
} }