Handling routes in a Laravel and Inertia app
If you're building an app with Laravel and Inertia, you don't have access to Laravel's helper methods because you're writing views in JavaScript. This means you lose the ability to generate URLs on the fly with Laravel's route
and action
helpers.
This short post outlines two ways to deal with routes in a Laravel and Inertia app.
Ziggy
The most popular way to solve this problem is with Ziggy. Ziggy is a Laravel package that shares your application's routes with the frontend.
First install Ziggy, and add its @routes
directive to your app template.
composer require tightenco/ziggy
<!doctype html><html> <!-- … --> <body> @routes @inertia </body></html>
After setting up Ziggy with Vue (read up on that in Ziggy's docs), you can access the route
function in your components.
<template> <InertiaLink :href="route('posts.index')"> All posts </InertiaLink></template>
The route
function also accepts parameters, just like Laravel's native route
helper.
<template> <InertiaLink :href="route('posts.show', { id: post.id })"> {{ post.title }} </InertiaLink></template>
Ziggy depends on route names. If you rather not name all your routes and use the action
helper, you'll need to resort to the next solution.
In models or resources
Another way to share routes with your frontend is by passing them down as data in your models or Eloquent resources.
<?php namespace App; use App\Http\Controllers\PostsController;use Illuminate\Database\Eloquent\Model; class Post extends Model{ protected $appends = [ 'links', ]; public function getLinksAttribute() { return [ 'show' => action( [PostsController::class, 'show'], $this->id ), ]; }}
A links
property will be appended when the Post
model gets serialized to JSON. You can then retrieve the URL from the post object in the frontend.
<template> <InertiaLink :href="post.links.show"> {{ post.title }} </InertiaLink></template>
Not all routes are tied to a model instance, for example an index
view for all posts. Routes like this can be passed down globally with Inertia::share
.
<?php namespace App\Providers; use App\Http\Controllers\PostsController;use Illuminate\Support\ServiceProvider;use Inertia\Inertia; class AppServiceProvider extends ServiceProvider{ public function boot() { Inertia::share('links', function () { return [ 'posts' => [ 'index' => action( [PostsController::class, 'show'], $this->id ), ], ]; }); }}
You can then access the global links
object on the $page
attribute.
<template> <InertiaLink :href="$page.links.posts.index"> All posts </InertiaLink></template>
If you don't want to clutter up your models, Eloquent resources are a great place to declare links too.
<?php namespace App\Http\Resources; use App\Http\Controllers\PostsController;use Illuminate\Http\Resources\Json\JsonResource; class Post extends JsonResource{ public function toArray($request) { return [ // 'links' => [ 'show' => action( [PostsController::class, 'show'], $this->id ), ], ] }}
At Spatie, we use resources for all data that gets passed down to views. We even created a package to reduce boilerplate when declaring links on resources.