Route Model Binding

Type-hint an Eloquent model on an argument named like a route segment, and Laravel 2,157 loads the row or answers 404. The bookshop's migration creates categories and products (with category_id, sku and slug) in SQLite 4,756 ; Category has hasMany(Product::class) (Eloquent Relationships).

Implicit binding by ID, by slug, and scoped to a parentPHP
Route::get('/products/{product}', fn (Product $product) => $product)
    ->name('products.show');
Route::get('/books/{product:slug}', fn (Product $product) => $product->name)
    ->missing(fn () => redirect()->route('products.index'));
Route::get('/categories/{category:slug}/products/{product:slug}',
    fn (Category $category, Product $product) => "{$category->name} / {$product->name}");
Output
$ curl -s http://127.0.0.1:8303/products/2
{"id":2,"category_id":2,"sku":"BK-1002","slug":"modern-php","name":"Modern PHP","price":34.5}
$ curl -i http://127.0.0.1:8303/products/999
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
...
        <title>Not Found</title>
$ curl -s -H 'Accept: application/json' http://127.0.0.1:8303/products/999 | jq -r .message
No query results for model [App\Models\Product] 999

The handler rendered the ModelNotFoundException as a 404 (Error Pages); the fallback never ran, because a route had matched. missing() turned the 404 for /books/no-such-book into a 302 to /products. The nested route is scoped through $category->products(): modern-php returned 200 under computing and 404 under fiction; scopeBindings() scopes plain {id} children too. #[RouteKey('slug')] on the model (or getRouteKeyName()) changes the default key, and ->withTrashed() binds soft-deleted rows.