-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
[12.x] Return unprocessable response when parameter is not a valid UniqueStringId #54033
Conversation
*/ | ||
public function isNotFound(): bool | ||
{ | ||
return $this->status === 404; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use \Symfony\Component\HttpFoundation\Request::HTTP_NOT_FOUND
here
return $this->status === 404; | |
return $this->status === Request::HTTP_NOT_FOUND; |
* | ||
* @var int | ||
*/ | ||
protected int $status = 404; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it make sense to extend the exception from \Symfony\Component\HttpKernel\Exception\HttpException
then?
src/Illuminate/Database/Eloquent/Concerns/HasUniqueStringIds.php
Outdated
Show resolved
Hide resolved
@@ -633,7 +634,8 @@ protected function prepareException(Throwable $e) | |||
{ | |||
return match (true) { | |||
$e instanceof BackedEnumCaseNotFoundException => new NotFoundHttpException($e->getMessage(), $e), | |||
$e instanceof ModelNotFoundException => $e->isNotFound() ? new NotFoundHttpException($e->getMessage(), $e) : new HttpException($e->getStatus(), $e->getMessage(), $e), | |||
$e instanceof ModelNotFoundException => new NotFoundHttpException($e->getMessage(), $e), | |||
$e instanceof InvalidIdFormatException => new HttpException(422, $e->getMessage(), $e), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use \Symfony\Component\HttpFoundation\Request::HTTP_UNPROCESSABLE_ENTITY
here
$e instanceof InvalidIdFormatException => new HttpException(422, $e->getMessage(), $e), | |
return $this->status === Request::HTTP_UNPROCESSABLE_ENTITY; |
|
||
$this->message .= " for model [{$model}]"; | ||
|
||
if (count($this->ids) > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified by omitting the function call and comparing it to an empty scalar value:
if (count($this->ids) > 0) { | |
if ($this->ids !== []) { |
public function setModel($model, $ids = [], ?string $field = null) | ||
{ | ||
$this->model = $model; | ||
$this->ids = Arr::wrap($ids); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you type-hint $ids
, you can simply do:
public function setModel($model, $ids = [], ?string $field = null) | |
{ | |
$this->model = $model; | |
$this->ids = Arr::wrap($ids); | |
public function setModel($model, array|int|string $ids = [], ?string $field = null) | |
{ | |
$this->model = $model; | |
$this->ids = (array) $ids; |
|
||
/** | ||
* @template TModel of \Illuminate\Database\Eloquent\Model | ||
*/ | ||
class InvalidIdFormatException extends \RuntimeException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it make sense to extend the exception from \Symfony\Component\HttpKernel\Exception\HttpException
then?
/** | |
* @template TModel of \Illuminate\Database\Eloquent\Model | |
*/ | |
class InvalidIdFormatException extends \RuntimeException | |
use Symfony\Component\HttpKernel\Exception\HttpException; | |
/** | |
* @template TModel of \Illuminate\Database\Eloquent\Model | |
*/ | |
class InvalidIdFormatException extends HttpException |
Thanks for your pull request to Laravel! Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include. If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions! |
This changes the behavior of the
HasUniqueStringIds::handleInvalidUniqueId()
method so that it returns a semantically correct HTTP response that can help callers determine the root cause of a failing response.If I pass an incorrectly shaped UUID (
1234-th!s-is-not-A-uuid-#^@b
) to a route that expects a UUID, returning a 404 is misleading. While it is true the model probably does not exist in the database and therefore is not found, the reality is that the request is failing validation. It is easy to assume that the response returned is the result of a DB query. (For instance, I tried to optimize routes by skipping route model binding because I didn't understand that the database was NOT being queried in this case).When
HasUniqueStringIds::isValidUniqueId()
indicates the key invalid, we throw a new custom exceptionInvalidIdFormatException
. It has been added to the Handler::$internalDontReport array, and when raised in the application during an HTTP request, gets converted to a 422 response.I targeted master because I believe this behavior change will break tests for users and therefore is not appropriate for a patch release.
Alternatives
ModelNotFoundException
. I'd be happy to pivot back to this if it makes more sense for the framework. It seems very muddy, but the newInvalidIdFormatException
duplicates much of what exists in that class.ValidationException::withMessages([$field => '???'])
. I'm not sure what the message should be in that case.