Framework: Partial Resource Routes only() except() why throw an error instead of 404 ?

Created on 4 Jul 2018  路  17Comments  路  Source: laravel/framework

  • Laravel Version: 5.6
  • PHP Version: 7.1.19

Description:

https://laravel.com/docs/5.6/controllers#resource-controllers

when i create a controller by php artisan make:controller TestController --resource --model=Test
and use route:
Route::resource('/test', 'TestController')->only(['index', 'store', 'edit', 'update', 'destroy']);
or
Route::resource('/test', 'TestController')->except(['create', 'show']);

if go to http://example.com/test/1 (actually this is route test.show)
why throw an error instead of 404?
Symfony \ Component \ HttpKernel \ Exception \
MethodNotAllowedHttpException

Most helpful comment

You code was wrong

Route::resource('/test', 'TestController', ['only' => ['index', 'store', 'edit', 'update', 'destroy']]);

Route::resource('/test', 'TestController', ['except' => ['create', 'show']]);

All 17 comments

You code was wrong

Route::resource('/test', 'TestController', ['only' => ['index', 'store', 'edit', 'update', 'destroy']]);

Route::resource('/test', 'TestController', ['except' => ['create', 'show']]);

but i following the Laravel 5.6 document
Partial Resource Routes
https://laravel.com/docs/5.6/controllers#restful-partial-resource-routes

Route::resource('photos', 'PhotoController')->only([
    'index', 'show'
]);

Route::resource('photos', 'PhotoController')->except([
    'create', 'store', 'update', 'destroy'
]);

your url matches valid route patterns but not for get method, so method not allowed is correct i think

as for it being an exception, laravel uses exceptions for things like this, even for 404s.
it just comes down to how that exception is handled (this will also be different for html/ajax and development/production)

thankyou for your reply
hmm it means if use Resource Routes we need make sure has all the seven methods ?
if yes, whats the case to use only() and except()?

and how to let the Resource Routes ignore 'create' and 'show' ? can i do something like this?

Route::get('/test/create', function () {
    return abort(404);
});

Route::get('/test/{test}', function () {
    return abort(404);
});

Route::resource('/test', 'TestController');

but this seems look weird ;(

Oops, i just checked route list by use php artisan route:list
there also has 5 route only, no 'create' and 'show'
suppose not on route list is 404 ?

or catch the method not allowed message and swap it for a not found

One unrelated thing, the first parameter to "resource" isn't a path but the resource name. I wouldn't expect to see a "/" in a resource name.

yep ok i removed the "/"
i tested 3 hours, and found some problem, i don't know what is this
i disabled the Route::resource, and use this instead

// Route::resource('test', 'TestController');

// Route::get('test', 'TestController@index')->name('test.index');
// Route::post('test', 'TestController@store')->name('test.store');
// Route::get('test/{test}/edit', 'TestController@edit')->name('test.edit');
Route::patch('test/{test}', 'TestController@update')->name('test.update');
// Route::delete('test/{test}', 'TestController@destroy')->name('test.destroy');

ok i un-comment ONE line each time from top to bottom, no abc this method in controller
and go to (GET) http://localhost/test/abc

->name('test.index');    // 404 , because not match, so is correct
->name('test.store');    // 404 , because not match, so is correct
->name('test.edit');      // 404 , because not match, so is correct
->name('test.update'); // error MethodNotAllowedHttpException, i was use GET, but this is for PATCH, ??
->name('test.destroy'); // error same as ->name('test.update'), this is for delete, why ??

Routes are working as they should. The errors you are seeing are triggered because test.update and test.destroy don't accept GET method that your browser is using to request the pages, hence the MethodNotAllowedHttpException.

Usually GET and POST requests that can't be resolved, trigger 404 error (NOT FOUND), and MethodNotAllowedHttpException trigger 405 error (METHOD NOT ALLOWED).

This has been defined in \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException that is used by \Illuminate\Routing\RouteCollection.

Summa summarum: PUT, PATCH and DELETE don't allow GET requests what your browser is using to access, so it tells you that. If you want to use those routes, you need to use Form Method Spoofing in your POST requests.

thankyou for your reply @ivuorinen
i know the Form Method Spoofing
but my problem is , when i go to http://localhost/test/abc (via GET, type the url in browser address bar)
and also GET /test/{test} is NOT in the route:list
why the GET request trigger the test.update and test.destroy
i want GET /test/{test} goes to 404
actually not in the route list is goes to 404, right ?

Then you need to allow GET, catch the request, check the method and if GET return your 404 error page.

Something like this:

# In your routes/web.php
Route::get('/test/{test}', 'TestController@update');
Route::patch('/test/{test}', 'TestController@update')->name('test.update');
# In your Controller
public function update(\Illuminate\Http\Request $request)
{
    if ($request->isMethod('GET')) {
        return abort(404, 'Your error message');
    }

    // Your code...
}

I didn't test these, but the logic should be fine.

ref to https://laravel.com/docs/5.6/controllers#resource-controllers
i don't need create and show route
Route::get('/test/create', 'TestController@create'); // this is equal to create
Route::get('/test/{test}', 'TestController@show'); // this is equal to show

not in the route:list still trigger the route, i don't know is this a bug or?
now i was using something like this in the controller to ignore the error details showing on the browser

public function create()
{
    abort(404);
}

public function show($test)
{
    abort(404);
}

but this not make sense ;(

if you want to understands the problem, just do a simple test

create a controller, run
php artisan make:controller TestController --resource

add route
Route::resource('test', 'TestController')->except(['create', 'show']);

go to the url in your browser
http://localhost/test/1
or
http://localhost/test/create

you will see an error instead of a 404/blank page

That is expected. The URL is valid, but is being accessed via a disallowed method.

A 404 means the resource doesn't exist. A 405 means the resource exists, but you're accessing it wrong.

so what the ->except() used for ?

and /test/create is not in the route:list

When you call except(['create', 'show']), the create and show routes simply aren't created.
The update route is still created, which uses the same URL structure as show, but a different method.

Since you didn't define a test/create url, test/create matches test/{test}, which is a valid URL defined for the PUT and PATCH methods, but not for GET.

yes @36864 get the point
which is a valid URL defined for the PUT and PATCH methods, but not for GET.
so if i put this line over on top of other routes, will this route still proccess ? even the form look like this

Route::get('/test/{test}', 'TestController@update'); // this is for update via GET

<form method="POST" action="/test/create">
    @method('delete')
    @csrf
</form>

Hi there,

Welcome to Laravel and we are glad to have you as part of the community.

Unfortunately this GitHub area is not a support area for general application issues. This is only for issues/bugs with the framework code itself.

I will be closing your ticket here. Instead please try asking your question on one of the many great community support areas that will likely give you a better answer more quickly:

  • Laravel Slack (https://larachat.co/)
  • Laravel.io Forum (https://laravel.io/forum)
  • Laracasts Forum (https://laracasts.com/discuss)
  • StackOverflow (http://stackoverflow.com/questions/tagged/laravel)

If you feel I've closed this issue in error, please provide more information about how this is a framework issue, and I'll reopen the ticket.

Thanks in advance.

Was this page helpful?
0 / 5 - 0 ratings