Skip to main content

Route Model Binding and API Resources

7/28
Chapter 2 Routing, Controllers, and Middleware

Route Model Binding and API Resources

16 min read Lesson 7 / 28

Route Model Binding

Route model binding automatically resolves Eloquent models from route parameters, eliminating manual lookup code.

Implicit Binding

// Laravel finds the Post by ID automatically
Route::get('/posts/{post}', function (Post $post) {
    return view('posts.show', compact('post'));
});

Custom Key Binding

Use a slug instead of ID:

// In the route
Route::get('/posts/{post:slug}', [PostController::class, 'show']);

// Or define it on the model
class Post extends Model
{
    public function getRouteKeyName(): string
    {
        return 'slug';
    }
}

Scoped Bindings

Automatically scope child models to their parent:

Route::get('/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    // $post is automatically scoped to the $user
    return view('posts.show', compact('user', 'post'));
})->scopeBindings();

Customizing Missing Model Behavior

Route::get('/posts/{post}', [PostController::class, 'show'])
    ->missing(function () {
        return redirect()->route('posts.index')
            ->with('error', 'Post not found.');
    });

API Resources for JSON Responses

Transform models into structured JSON:

php artisan make:resource PostResource
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'slug' => $this->slug,
            'excerpt' => Str::limit($this->body, 150),
            'published_at' => $this->published_at?->toISOString(),
            'author' => new UserResource($this->whenLoaded('author')),
            'tags' => TagResource::collection($this->whenLoaded('tags')),
            'links' => [
                'self' => route('api.posts.show', $this),
            ],
        ];
    }
}
// In controller
public function index(): AnonymousResourceCollection
{
    return PostResource::collection(
        Post::with(['author', 'tags'])->published()->paginate(15)
    );
}