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
[11.x] Improve API error handling #47317
base: master
Are you sure you want to change the base?
Conversation
|
I faced the same issue recently, since my app did not have any route named Laravel core must not auto assume that the this route exists in Skelton |
| Route::get('test-route', fn () => throw new AuthenticationException); | ||
|
|
||
| $this->assertFalse(Route::has('login')); | ||
|
|
||
| $this->get('test-route') | ||
| ->assertStatus(401) | ||
| ->assertSeeText('Unauthenticated.'); |
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.
When would an application not have a login route, but yet still have routes protected by auth that would throw an authentication exception like this?
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.
When you're using any other auth mechanism, e.g. token in the headers or query.
| return $this->shouldReturnJson($request, $exception) || ! $redirectTo | ||
| ? response()->json(['message' => $exception->getMessage()], 401) | ||
| : redirect()->guest($exception->redirectTo() ?? route('login')); | ||
| : redirect()->guest($redirectTo); |
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.
Correct me if I'm wrong, but with this logic it is currently possible for a route to return a JSON response when it's not expected to, if there is no $redirectTo target. Is this correct behaviour?
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.
Yes, that's exactly the point of this change.
I am arguing that receiving 500 | Server error or Route [login] not defined. is wrong (and is not useful) if the actual issue is that you're not authenticated and returning the JSON message is the most reasonable fallback in that case.
|
Going to revisit this a bit later. I'm currently doing some heavy work on the skeleton, exception handler, etc. |

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

I've come across two common issues when working with API backends and testing the endpoints in browser or just not knowing to specify the
Accept: application/jsonheader. Most projects work around this by adding some middleware that either adds the header to all incoming API requests or sets aforceJsonflag on their custom request.This PR proposes to remedy these issues by taking a "only redirect if there's a reasonable redirect target" approach.
Unauthenticated user
When hitting an endpoint that requires authentication, but failing the auth, user should receive an authentication error. Instead they receive a 500 error with
Route [login] not defined.message.Proposed solution: only redirect to
route('login')if the route exists. Otherwise fall back to JSON response.Backwards compatibility? Technically it is a breaking change, but I can't imagine a legit scenario where someone would rely on their auth errors being redirected to non-existant route, catching the particular error and doing some useful reporting with it.
Validation error
When getting some request params wrong, users should see validation errors. Instead users that are hitting the endpoint in their browserse receive a redirect to
/. Because no "previous" route exists and even if it did, Laravel wouldn't know it as the session is not enabled on API routes.Proposed solution: only redirect to "previous" route if it exists in the session. Do not use
url()->previous()asurl('/')for all validation errors is unlikely to be useful in real usecases (although common in automated tests)Backwards compatibility?
302redirect now. Two options:422instead of302, i.e. changeassertRedirectorassertStatus(302)toassertInvalidorassertStatus(422).session()->setPreviousUrl($prevUrl);to the test before hitting the endpoint that should redirect you back.invalidmethod or catching the exceptions in handler (and maybe just specifying->redirectTo('/')on them which is still respected).