How to handle Laravel validation errors using VueJS 3, Axios, and Toast Notification
Handling Laravel validation errors on a Vue.js 3 front end sounds straightforward, but it becomes tedious fast once you have more than a couple of API calls.
Here is how axios handles errors:
axios.get('/api/users')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
// Handle the errors
console.log(error.response.data.errors);
});
Using the catch method in axios, you can present errors to the user. If you only have one or two API calls, handling error messages individually works fine. But when you have a dozen API calls, repeating that logic in every catch block is a waste of time.
axios offers a feature called interceptors that intercepts requests or responses before they reach then or catch.
Here is what that looks like:
axios.interceptors.response.use(response => {
// Do something with the response
// For example: Only return the data
return response.data;
}, error => {
// Handle the errors
alert(error);
return Promise.reject(error);
});
Now let us put this into practice.
In my project, I have a file named http.js that serves as an axios helper:
import axios from 'axios';
const client = axios.create({
baseURL: import.meta.env.VITE_APP_API_URL,
withCredentials: true, // required to handle the CSRF token
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
export default client;
If you do not already have something like this in your project, create one. It saves you from repeatedly importing and configuring axios everywhere.
Here is how to use the http helper:
import http from "@/services/http";
http.get('api/users');
Clean and simple.
For displaying notifications, I use the vue-toast-notification package. Let us integrate it with axios to handle validation errors automatically.
Install vue-toast-notification - npm:
npm install vue-toast-notification@^3.0
Then create a file named notify.js:
import { useToast } from 'vue-toast-notification';
import 'vue-toast-notification/dist/theme-sugar.css';
const $toast = useToast({
position: 'top-right',
dismissible: true,
duration: 2000,
});
export default class Notify {
static success(msg) {
$toast.success(msg);
}
static error(msg) {
$toast.error(msg);
}
}
The Notify class can now be used from anywhere in the project:
import Notify from "@/services/notify";
Notify.error("An error ocurred!");
Go back to the http.js file and add the response interceptor:
import Notify from "@/services/ui/notify";
client.interceptors.response.use(response => {
return response;
}, error => {
if (error.response.status === 422 && error.response.data?.errors) {
Notify.error(Object.values(error.response.data.errors).flat().join("\n"));
}
return Promise.reject(error);
});
export default client;
From this point on, the interceptor handles all validation error messages and displays them to the user automatically.
You can still access the
errorobject inside thecatchmethod because the interceptor returnsPromise.reject.
Summary
- Centralized HTTP client -- create an
axioshelper file so you configure headers, base URL, and credentials in one place. - Interceptors over repetition -- use
axiosresponse interceptors to handle validation errors globally instead of duplicating logic in everycatchblock. - Toast notifications -- wrap a toast library in a
Notifyclass for a consistent, reusable notification API across your project. - 422 status check -- specifically target Laravel's 422 validation response status and extract the error messages from
error.response.data.errors.