Inertiajs - Laravel: How to Throw custom Error - laravel

How isit possible to throw an custom Error from Laravel in Inertiajs.vue without redirecting then?
Vue Component:
Inertia.post('company-organisations-create', {
name: this.newOrganisation.name,
description: this.newOrganisation.description
},
{
preserveScroll: true,
onSuccess: (page) => {
return Promise.all([
window.Toast.success(this.$page.props.toast.message),
this.newOrganisation.name = '',
this.newOrganisation.description = '',
])
},
onError: (errors) => {
window.Toast.error(errors.toastMessage)
}
});
LaravelController():
public function createOrganisations(Request $request)
{
try {
CompanyOrganisations::create([
'company_id' => $companyID,
'name' => $orgName,
'description' => $orgDescription,
]);
} catch(Excpetion) {
// Create Inertia Error 'onError'
/* As example with json response
return response()->json([
'message' => 'ups, there was an error',
], 403); */
}
return Redirect::route('company.organisations',
)->with([
'toastMessage' => 'Organization created!'
]);
}
As Im not able to receive json format in Inertia request, I need to throw a error in Inertiajs.vue Component.
Thank you very much.

Try this:
try {
// ...
} catch(Excpetion) {
return redirect()->back()->withErrors([
'create' => 'ups, there was an error'
])
}
The errors should be received onError
onError: (errors) => {
window.Toast.error(errors.create)
}

Related

Cannot catch error in promise chaining Larave-vue2 SPA authentication

I try to authenticate in Laravel9 Sanctum a SPA using vue3 and vuex, not with the token authentification but with the SPA Authentication.
I am not very used to the javascript language, and even less to promise chaining.
The first thing I am trying is registration.
Here are my methods.
The backend registration method
public function register(Request $request)
{
$request->validate([
'name' => 'required|string',
'email' => 'required|email|string|unique:users,email',
'password' => [
'required',
'confirmed',
Password::min(8)->mixedCase()->numbers()->symbols()
]
]);
$user=User::create([
'name' => $request['name'],
'email' => $request['email'],
'password' => bcrypt($request['password'])
]);
return response (['user'=>$user]);
}
The frontend registration method in the register.vue
//is actually the register form's data
const user = {
name: "",
email: "",
password: "",
password_confirmation: "",
};
function register(ev) {
ev.preventDefault();
store
.dispatch("register", user)
.then((data) => {
console.log("data in vue");
console.log(data);
router.push({
name: "Login",
});
})
.catch((error) => {
if (error.response.status === 422) {
errors = error.response.data.errors;
}
});
}
the actions method in the store/index.js
actions: {
register({ commit }, form) {
console.log("in register of index");
axiosClient.get("/sanctum/csrf-cookie");
return axiosClient.post("/api/register", form).then(({ data }) => {
console.log("data dans index");
console.log(data);
return data;
});
},
...
The registration is working fine but when I try an already existing email in the registration form, I get a status 422 as expected and this response from the axiosClient.post('/api/register',form):
{"message":"The email has already been
taken.","errors":{"email":["The email has already been taken."]}}
I expect this error to be intercepted by the catch in the register view but it doesn't happen. Despite this error I continue to use the .then and to push the Login route which is not what I want.
Can somebody tell me where I am doing wrong ?
I completely forget that in my axios.js there were interceptors that triggered this wrong behavior.
All is clear now.

how can I customize json responses of laravel api and show them in vuex

Trying different solutions, I am fooling around with
response()->json([ ])
To create responses that I can read in my vue / vuex application
The Laravel api function that stores a new Speler ( dutch for player ;)):
I have trouble sending the created, or found Speler-object, through the response to the vuex-store.
Tried to set the status to 202 when succesfully logged, yet the actual status sent is 200..
It is clear that I do not understand it well enough. Can anyone help and explain?
public function store(Request $request)
{
if (Game::where('id',$request['game_id'])->exists() ){
if (!Speler::where('name',$request['name'])->where('game_id',$request['game_id'])->exists()){
$newSpeler = Speler::create(
[
'name' => $request['name'],
'pass_code' => $request['pass_code'],
'game_id' => $request['game_id']
])->first());
return $newSpeler;
}
elseif ( Speler::where('name',$request['name'])->where('game_id',$request['game_id'])->where('pass_code', $request['pass_code'])->exists()){
$speler = Speler::where('name',$request['name'])->where('game_id',$request['game_id'])->where('pass_code', $request['pass_code']);
return response()->json(['speler'=> $speler, 202]);
}
return response()->json(['status' => 'This name is already used, pass-code is not correct', 409]);
}
return response()->json([ 'status' => 'The game-pin does not exist', 403 ]);
}
This is called form the vuex actions:
export const addSpeler = ({commit}, formData) => {
return new Promise((resolve, reject) => {
fetch(`api/speler`, {
method: 'post',
body:formData,
})
.then(res => {
if (res.status === 202){
resolve('De speler is succesfully logged on');
commit('SET_CURRENT_SPELER', res.data.speler);
}
else if (res.status === 201){
commit('SET_CURRENT_SPELER', res.data);
resolve('De speler is succesfully added')
}
else {
reject('De speler is not logged in. Name exists and does not match passcode');
}
})
.catch(err => {
reject(err.message)
});
})
}
and this is called from a vue method:
methods: {
addSpeler(){
this.errorMessage ='';
this.spelerAdded =false;
const formData = new FormData();
formData.append('name', this.name);
formData.append('pass_code',this.pass_code);
formData.append('game_id', this.currentGame.id);
this.$store.dispatch('addSpeler', formData )
.then(res => {
this.spelerAdded = true;
console.log(res.status);
})
.catch(err => {
this.errorMessage = err;
this.spelerAdded = false;
});
},
mutations.js:
export const SET_CURRENT_SPELER = (state, speler) => {
state.currentSpeler = speler;
}
state.js:
export default{
currentGame:{},
currentSpeler:{}
}
The comment by porloscerros answered the question perfectly :
the status goes as the second argument of the json method return response()->json(['speler'=> $speler], 202); (and not inside the array as you are doing). If you don't pass a second argument, the argument value is assigned to 200 by default json(mixed $data = [], int $status = 200, array $headers = [], int $options = 0)

Axios returns error status code 500 when there is data present

I am using Laravel 8, VueJS and Axios for my application then every time I try to fetch all records from my database it returns an error with status code 500. Even though when fetching the data using Postman/Insomnia it returns the data without an error.
I tried to empty the table where it fetches the data the error disappears and it returns empty data with status code 200.
Store Module:
import axios from 'axios'
export default {
namespaced: true,
state: {
courses: [],
teacher: '',
},
getters: {
allCourses(state) {
return state.courses
},
},
actions: {
async fetchAllCourses({ commit }) {
const response = await axios.get('teacher/course-management/list')
console.log(response.data.data)
commit('SET_COURSES', response.data.data)
}
},
mutations: {
SET_COURSES(state, courses) {
state.courses = courses
}
}
Controller:
public function fetchAllCourses() {
try {
$courses = Course::all()->sortBy('id');
$data = $courses->transform(function ($course) {
// ! Get teacher id
$teacherId = $this->user->teacher->id;
// ! Get teacher name by id
$teacherName = $this->getTeacherName($teacherId);
return [
'id' => $course->id,
'teacher_id' => $course->teacher_id,
'teacher' => $teacherName,
'section' => $course->section,
'code' => $course->code,
'status' => $course->status,
'image' => $course->image,
];
});
return $this->success('Request success', $data);
} catch (\Exception $e) {
return $this->error($e->getMessage(), $e->getCode());
}
}
Problem solved.
public function fetchAllCourses() {
try {
$courses = Course::all()->sortBy('id');
$data = $courses->transform(function ($course) {
return [
'id' => $course->id,
'teacher_id' => $course->teacher_id,
'teacher' => $this->getTeacherName($course->teacher_id),
'section' => $course->section,
'code' => $course->code,
'status' => $course->status,
'image' => $course->image,
];
});
return $this->success('Request success', $data);
} catch (\Exception $e) {
return $this->error($e->getMessage(), $e->getCode());
}
}

How to store validator errors into an object with Laravel and Vue.js

I am using Laravel 7 and Vue.js 2.
I made a form that should show a table if every field has been inserted.
I made also a server-side validation to check if all fields are correctly inserted.
This is the function that creates a call to the server with Axios:
runReport: function() {
const url = "api/get_report?room="+this.formReport['room']+"&participant="+this.formReport['participant']+"&start="+this.formReport['start']+"&end="+this.formReport['end'];
axios.get(url)
.then((response) => {
console.log(response.data.data);
this.meetingsReport = response.data.data;
alert('viva');
this.$emit('passMeetings', this.meetingsReport);
this.$emit('success');
})
.catch(function(error) {
console.log(error.response.data);
this.errors = error.response.data; //problem
alert('noviva');
});
}
This is the validator in the controller:
$validator = Validator::make($request->all(), [
'room' => 'required',
'start' => 'required',
'end' => 'required',
'participant' => 'required',
]);
if ($validator->fails()) {
return response($validator->errors(), 422);
}
If everthing has been correctly inserted in the form I have no problems, but if I missed a field I am unable to store the errors in an empty object that I created called errors.
UPDATED: This is the response from the validation failed (status 422):
{
"room": [
"The room field is required."
],
"participant": [
"The participant field is required."
]
}
I suppose the problem is that I am unable to access to this.errors from the catch block of Axios.
this in the context of an anonymous function doesn't point to the vue instance, so you may need to bind this to the function or use arrow function within the catch block
.catch(error => {
console.log(error.response.data);
this.errors = error.response.data; //should not be any - problem
alert('noviva');
});
At the end I solved using the keyword self in the axios call. In this way I was able to connect the catch block with Vue.js component.
This is the code:
runReport: function() {
let self = this;
const url = "api/get_report?room="+this.formReport['room']+"&participant="+this.formReport['participant']+"&start="+this.formReport['start']+"&end="+this.formReport['end'];
axios.get(url)
.then((response) => {
console.log(response.data.data);
this.meetingsReport = response.data.data;
alert('viva');
this.$emit('passMeetings', this.meetingsReport);
this.$emit('success');
this.errors = {};
})
.catch(function(error) {
console.log(error.response.data);
self.errors = error.response.data;
self.$emit('failure');
});
}

Laravel Validation with vue js

i want to post ajax request using vue-resource this.$http.post request. it worked perfectly fine if i passed all validation rules but i want to get some validations if it fails. so far i keep getting 500 error if i don't fill out some input fields. it's hard for me to debug the error because it didn't appeared on the network tab.
here's what i've done so far
//my modal component
<script>
export default {
props: ['show'],
data() {
return {
input: {
id: '',
name: '',
address: '',
email: ''
},
errorInputs: {}
}
},
methods: {
createStudent() {
this.$http.post('/students', this.$data.input)
.then((response) => {
alert('added new row!)
}, (response) => {
console.log(response.data);
});
}
}
}
</script>
// my controller
public function store(Request $request) {
$validator = $this->validate($request,[
'id' => 'required',
'name' => 'required|unique:students',
'email' => 'required|unique:students|email',
'address' => 'required',
]);
if($validator->passes()){
Student::create($request->all());
return response()->json([], 201);
}
$errors = json_decode($validator->errors());
return response()->json([
'success' => false,
'message' => $errors
],422);
}
any helps and references would be appreciated. i am using laravel 5.3 and vue js 2
$this->validate() returns 422 error response alongside your validation errors, so you should get those errors in then() second callback (like you do now). Your vue component body should be like this:
{
data() {
// ...
},
createStudent() {
this.$http
.post('/students', this.input)
.then(this.handleSuccess, this.handleError)
},
handleSuccess(res) {
alert('student created')
},
handleError(res) {
if (res.status === 422) {
this.errorInputs = res.body
} else {
alert('Unkown error!')
}
}
}
Remember to add v-model="input.fieldName" properties to your inputs.
Remember to include your session token along with your post, unless of course you are disabling csrf tokens for that route.
Since Laravel 5.1 you can disable this in your verifytoken middleware
<?php namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as ...
class VerifyCsrfToken extends ... {
protected $except = [
'payment/*',
];
}

Resources