Statamic Peak

Article

The error pages with Laravel and InertiaJS

How to customize error pages with Laravel and InertiaJs ? It's all you need to know !

By design, Laravel handles automatically the error pages. They are detailed in development mode and contains informations on the error causes. In production mode, they are very generic and only contains a message, preventing a data leak.

By adding Inertia, the default Laravel running does not exactly fit. As errors are not Inertia responses, they are opened into a modal, which doesn't really makes sense.

We will then make modifications to get a true redirection to a personalized page!

If you're interested in Laravel, I'm preparing a Laravel Compendium, which can be available in early access. There is also another article on the subject: Translate Laravel Jetstream and Inertia.

Display an Inertia response as a Laravel error

The Inertia documentation explains the process. We add a render function to our App\Exception\Handler.php, the same class we would modify if we added a tool like Sentry or Flare.

use Throwable;
use Inertia\Inertia;

/**
 * Prepare exception for rendering.
 *
 * @param  \Throwable  $e
 * @return \Throwable
 */
public function render($request, Throwable $e)
{
    $response = parent::render($request, $e);

    if (!app()->environment(['local', 'testing']) && in_array($response->status(), [500, 503, 404, 403])) {
        return Inertia::render('Error', ['status' => $response->status()])
            ->toResponse($request)
            ->setStatusCode($response->status());
    } else if ($response->status() === 419) {
        return back()->with([
            'message' => __('The page expired, please try again.'),
        ]);
    }

    return $response;
}

In this function, we get the default Laravel response. If we are in development mode, we simply throw it back and get a display of the Ignition view into a modal. In production mode, we throw an Inertia response that we can customize.

As always in Inertia, we specify in Inertia::render the name of the component we want to display. In our example, it is the resources/js/Pages/Error.vue file.

Then, because it is a classic Inertia response and a Vue component, wee can do whatever we want : get datas from the server as props, translate the content, etc...

<template>
    <app-layout :public-site="true">
        <div v-if="status === 404">
            <div class="container">
                <div>
                    <div>
                        <h1>404</h1>
                        <h2>Vous êtes perdu... ?</h2>
                        <p>Ne vous inquiétez pas...<br/>
                            <strong>Nous pouvons tout de même vous aider à trouver une maison !</strong></p>
                        <a :href="route('find-a-home')" class="mt-4">Trouver une maison maintenant !</a>
                    </div>
                </div>
            </div>
        </div>
        <div v-else>
            <h1>noparse_b7f3919a99d4093361004e8fd25d5a1e</h1>
            <div>noparse_e976016c7fa0a88cf04d9d783cbd57e1</div>
        </div>
    </app-layout>
</template>

<script>
import AppLayout from "@/Layouts/AppLayout";
export default {
    components: {AppLayout},
    props: {
        status: Number,
    },
    computed: {
        title() {
            return {
                503: '503: Service Indisponible',
                500: '500: Erreur',
                403: '403: Accès refusé',
            }[this.status]
        },
        description() {
            return {
                503: "Désolé, nous sommes en train d'effectuer une maintenance. Revenez plus tard.",
                500: 'Oups, une erreur est survenue.',
                403: "Désolé, vous n'avez pas accès à cette page.",
            }[this.status]
        },
    },
}
</script>