I've never seen anything like this, but I have a routes file that works just fine when you're using the dev site in Chrome, but fails to distinguish between these two routes using Postman or Codeception:
POST conference/attendees/{token} AttendeeController@updateByToken
GET|HEAD conference/attendees/{token} AttendeeController@showByToken
When I do a post request in testing or in Postman, the GET function is used. However, if I comment out either the POST or the GET route in the routes file, the request then fails completely. Any idea how this could be?
Also, if I turn the POST request into an anonymous function, I see the function invoked correctly. I've verified that the names of the functions in AttendeeController are correct.
UPDATE: For whatever reason, removing the custom form request allows the correct function to process the POST request, which I have verified is, in fact, a POST. The correct errors from a failed request are returned to the dev site in Chrome but in the case of Postman and Codeception, the function assigned to the GET route handles the request in error.
UPDATE AGAIN: I removed the custom form request and it worked. I then replaced that form request with another and when authorized was set to false, it returned Forbidden as expected. As soon as I added a rule 'email' => 'required' it immediately went back to forwarding the request to the GET route rather than returning the custom error messages.
UPDATE AGAIN AGAIN: Based on a conversation in Slack I tried changing the name of the endpoints to be different. Here's what is happening:
422 unprocessable like I would expect.For whatever reason, it appears that the form request is causing the issue by not returning the correct status code and, somehow, trying to use a route of the same name but as a GET request. This is all now above my head, just reporting what I'm seeing.
For postman, you need to change request type to POST if you want to check post request.
Of course, that has been done. The issue is that when a form request fails Laravel is looking for a different route rather than returning an "unprocessable".
@mcblum You probably have not set a value for the $redirect, $redirectRoute or $redirectAction property of your FormRequest object.
You can find these properties in the Illuminate\Foundation\HttpFormRequest class.
If validation fails the failedValidation method of this class is called, which throws a ValdationException with a response that is generated in the response method of the class. This response is a redirect, and the URL for this redirect is determined by a call to the getRedirectUrl method of the FormRequest class. If none of the properties I mentioned above are set this method falls back to the previous method of the Illuminate\Routing\UrlGenerator class:
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Routing/UrlGenerator.php#L136
And here the URL of your POST request is returned, resulting in a redirect to the GET route for this URL.
@janhenkgerritsen Woah. Is this new in 5.3? I have never in my life set the $redirect, $redirectRoute or $redirectAction variables in a form request. Before, any failures would simply return the errors as JSON. How do I get it to do that again?
Thank you for the explanation.
Edit: Found this in the docs:
In this example, we used a traditional form to send data to the application. However, many applications use AJAX requests. When using the validate method during an AJAX request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code.
If that isn't happening, could it be that it doesn't see the Postman and Codeception requests as AJAX? If that's true, is there any way to tell my code to universally treat requests as AJAX?
Ok, after a week of working on this, @janhenkgerritsen saved the day (again). By digging through the code I was able to find that if I added this function to /app/Http/Requests/Request.php Laravel treated all of my requests as AJAX:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
/**
* Treat every single request as AJAX
*
* @return bool
*/
public function ajax()
{
return true;
}
}
Hopefully this will be useful to someone else -- please feel free to mark this as closed.
Most helpful comment
Ok, after a week of working on this, @janhenkgerritsen saved the day (again). By digging through the code I was able to find that if I added this function to /app/Http/Requests/Request.php Laravel treated all of my requests as AJAX:
Hopefully this will be useful to someone else -- please feel free to mark this as closed.