Laravel and Vue.js: How to Display Validation Errors

In this example, we will show how to validate Vue.js form and display error messages from Laravel. Let's say we have a simple form to collect the user's name and email for our mailing list.

For this demonstration, we used Laravel Breeze starter kit with Vue preset.

Invalid Form


Request validation and API Controller

Create the MailingListRequest class with validation rules for name and email.

app/Http/Requests/MailingListRequest.php

namespace App\Http\Requests;
 
use Illuminate\Foundation\Http\FormRequest;
 
class MailingListRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
 
public function rules(): array
{
return [
'name' => 'required|string',
'email' => 'required|email',
];
}
}

Then make API Controller. It will validate fields using MailingListRequest and return a success message if validation passes.

app/Http/Controllers/Api/MailingListController.php

namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use App\Http\Requests\MailingListRequest;
 
class MailingListController extends Controller
{
public function store(MailingListRequest $request)
{
// process data
 
return response()->json(['message' => 'Thank you']);
}
}

Define API route.

routes/api.php

use App\Http\Controllers\Api\MailingListController;
 
Route::post('/mailing-list', [MailingListController::class, 'store']);

Now, we can make a Vue form to submit to the API endpoint. If the data presented is invalid, the response will have a 422 response status, and Axios will throw an error. We catch the error and assign error messages from the response to the errors variable to display those messages in the form.

resources/js/Pages/Subscribe.vue

<script setup>
import { reactive, ref } from 'vue';
 
const errors = ref({})
const success = ref('')
 
const form = reactive({
name: '',
email: ''
});
 
function submit() {
axios.post('/api/mailing-list', form)
.then(response => success.value = response.data.message)
.catch(error => {
if (error.response.status === 422) {
errors.value = error.response.data.errors
}
})
}
</script>
 
<template>
<div class="bg-gray-50 min-h-screen pt-12">
<div class="max-w-md mx-auto bg-white rounded shadow-sm p-6 text-gray-900">
<span class="text-green-600" v-if="success">{{ success }}</span>
<form v-else class="flex flex-col space-y-4" @submit.prevent="submit" novalidate>
<div class="flex flex-col space-y-2">
<label>Name</label>
<input type="text" class="rounded" v-model="form.name">
<span class="text-red-600" v-if="errors?.name">{{ errors.name[0] }}</span>
</div>
 
<div class="flex flex-col space-y-2">
<label>Email</label>
<input type="email" class="rounded" v-model="form.email">
<span class="text-red-600" v-if="errors?.email">{{ errors.email[0] }}</span>
</div>
 
<button class="bg-gray-500 text-white rounded px-3 py-2">
Subscribe
</button>
</form>
</div>
</div>
</template>

When validation passes, a success message will be displayed instead of a form.

Success Message

avatar

I'm new to Laravel and Vue never used them before, not even php. I had to validate some input that only could be validated in the backend. I was looking for some way to pass the response to the frontend without losing any data in the page. This was the easiest and quickest solution!

👍 1
avatar

I would advise against this method, considering that you are using Laravel + Vue with Inertia you shouldn't even be using axios plus this doesn't handle routing at all. Use the code in the Inertia documents - https://inertiajs.com/validation what is the point of using Laravel if you are just gonna make a js implementation.

avatar

Not all projects uses Inertia and this article has nothing to do with Inertia. If you advise against something please explain why and give some more context.

There also can be cases where you don't even have control on 3rd party endpoints.

This article is about consuming API and displaying validation errors and not about Inertia and routing, however I understand what you're trying to say, but it doesn't feel like there's appropriate context.

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 79 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials