Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MickBee's avatar

Route model binding not working for api routes.

Hi,

What is going on here (Laravel 7):

//My Test
public function can_delete_book()
    {
        $book = create(Book::class);
        $this->delete(route('books.destroy',$book));
    }

//My api.php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::apiResource('books', 'BookController');
});


//My controller
public function destroy(Book $book)

When I inspect the $book in the controller, it is just a new book, not the one I passed in?

EDIT: Just noticed that it works for web routes but but not the api ones. Do we not use route model binding with the api routes?

Cheers,

Mick

0 likes
14 replies
bugsysha's avatar

Check in HTTP Kernel if you have \Illuminate\Routing\Middleware\SubstituteBindings::class under API middleware group.

1 like
MickBee's avatar

Or is it because I have WithoutMiddleware in my test.............

tykus's avatar

You can pass an array of middlewares that you want to have excluded to the withoutMiddleware method in your test example. This will allow you to only exclude the specific middleware(s) that you did not want to run.

bugsysha's avatar

What is the value of the test without middleware?

tykus's avatar

It depends on what the middleware you want disabled does, for example, we have a number of endpoints that have custom headers which are checked in a series of middlewares; but building these headers up for a simple test example is tedious, and noisy, so we disable that middleware for most tests and make a separate test for the middleware itself.

bugsysha's avatar

Why don't you build a helper which will handle that? By disabling you are allowing undetected bugs to stay hidden.

tykus's avatar

By disabling you are allowing undetected bugs to stay hidden.

In your opinion.

This approach works; our middleware is tested separately. Our functional test examples are concise, readable and are very apparent what exactly is being tested.

bugsysha's avatar

Not just my opinion. Practice showed that. I understand what you are saying cause I know how appealing clean tests are.

tykus's avatar

Practice showed that.

Then I would argue that there are missing tests.

bugsysha's avatar

Then I would argue that there are missing tests.

I can confirm/guarantee that there are always some tests that are missing.

tykus's avatar

I can confirm/guarantee

For your apps maybe 😉

</debate>

abdulrehman25's avatar

After searching for 2 hours I got the issue details

For route binding to work, your type-hinted variable name must match the route placeholder name

For example my edit method

Here is my route URI for the edit

user/role/{role}/edit

As you can see there is {role} placeholder in the route definition, so the corresponding variable must be called $role.

public function edit(Role $role)
{
   return view('role.edit',compact('role'));
}

Please or to participate in this conversation.