Laravel: Redirect the user to a custom 404 page when the given params are invalid - laravel

I made an application where a user can create some papers and see all data in a template. Every paper has a joincode which is generated at its creation.
I defined the join route in my web.php like this:
Route::get('/conceptPaper/lobby/{joincode}', 'App\Http\Controllers\ConceptPaperController#join');
and the join function in the controller the following way:
public function join($joincode)
{
try {
$conceptPaper = ConceptPaper::where('join_code', $joincode)->firstOrFail();
return response()->json($conceptPaper);
} catch(ModelNotFoundException $e)
{
return view('errors.404');
}
}
I used firstOrFail to check if the join code exists. If it exists it should return a response, otherwise it should redirect the user to a custom 404 page.
I created a custom component which gets the join code as a route param and shows the concept paper
{
path: '/conceptPaper/lobby/:joincode',
name: 'conceptPaper',
component: () => import('./views/ConceptPaper.vue')
},
So when the user joins a lobby with the right code he gets redirected to the page with all data from the corresponding paper:
showPaper: async function (conceptPaper) {
const joinCode = conceptPaper.join_code;
this.$router.push({ name: "conceptPaper", params: { joincode: joinCode }, });
},
My problem is that when the user types in the wrong code he still gets redirected to the view. When I check the response in the network tab its shows the 404 page.
I think I built it fundamentally wrong. Can anyone tell me how to do it the right way? When the suer types in the correct join code he should see the ConceptPaper.vue view. When the code is wrong he should be redirected to the 404 page.

From your code I'm assuming that you're using VueJs as an SPA and you're retrieving the data from your laravel backend API.
Based on that, your join function is supposed to return json data that you use in your frontend, but in case the ConceptPaper was not found, you return a view instead of json, which won't change much because you're just changing the data that your front-end receives, but the front-end component is not changed.
What I'd do is remove the try catch block, which will return a 404 response from the API, and handle the 404 case in vue, and create a NotFound view in vue.
Laravel
public function join($joincode)
{
$conceptPaper = ConceptPaper::where('join_code', $joincode)->firstOrFail();
return response()->json($conceptPaper);
}
Vue
router/index.js
const routes = [
// previous routes
{
path: '/not-found',
name: 'NotFound',
component: () => import('../views/NotFound.vue')
}
]
NotFound.vue
<template>
// page here
</template>
export {
name: 'NotFound'
}
And finally handle the not found API call, if you are using axios
axios.get('/conceptPaper/lobby/-1000')
.catch(function (error) {
if (error.response.status === 404) {
this.$router.push('NotFound');
}
});

Related

Is it possible for nuxt to determine what page is using the /slug path?

I have a post page and a category page in my project as well as the usual internal pages.
Right now I have the following structure in the pages folder:
pages/category/_id.vue - I send a request for a category
pages/post/_id.vue - send request for post
pages/page/_id.vue - send request for page.
The api for the project is written in laravel (don't know if it matters).
I want nuxt to know which request to send, to fetch category or post, and then choose desired template to display category or post. If there is no category or post, then make redirect to the page 404. Is it possible?
The API provider doesn't matter in this case. Only the logic within Vue/Nuxt page template lifecycle.
Every page template so category / post / page with provided id can use different endpoint to fetch the data from API.
Which Nuxt? 2 or 3?
In Nuxt 2 You should use asyncData of specific page template ex: post:
async asyncData ({ store, $axios, params, error }) {
return $axios.get(`${apiEndpoint}/posts`, {
params: {
id: params.id
}
}).then(item => {
if (item.data.length === 0) throw({ statusCode: 404, message: 'Post not found' })
return { item: item.data[0] }
}).catch(e => {
error(e)
})
}
If You want to force 404:
try {
} catch (err) {
if (err.response.status === 404) {
return this.$nuxt.error({ statusCode: 404, message: err.message })
}
}

Nuxt.js router.push doesn't fully redirect to another page while using asyncData query

I am using asyncData query in one of my pages:
async asyncData({$axios, query}) {
const id = query.id;
try {
const {data} = await $axios.$get(`http://localhost:8000/api/question/${id}`);
return {
question: data
}
} catch (e) {
console.log(e);
}
},
Whenever I try to access another route from this page, for example:
#click="$router.push('/solution'); addTodo(question.keywords); addTodo(option.keywords)">
It redirects me to this page /solution, but the request to access API still goes from previous page (question/id)
Accessing localhost:3000/solution page:
CORS works in every other page, so I think the issue is here with redirections.
What would be possible solutions to fix this?
Also, this is what I see in Network tab:
I think referer should be: localhost:3000/solution
Adding 'paths' => ['api/*'] to Laravel back-end CORS config helped.

Axios Get request return html not data SPA

need some help. I'm trying to fetch data from my db using axios. My backend is Laravel. I have a 200 status http request but it returns the whole html not the data I'm expecting.
Here is my code for route
Route::get('/home', 'PostController#ajaxCall');
Route::post('/home', 'PostController#store');
Route::get('/{any?}', function () {
return view('welcome');
});
Here is my code for Home.vue for Axios request
export default {
components: {addForm},
data () {
return{
posts:[]
}
},
created() {
axios.get('/home').then(response => this.posts = response.data);
}
}
For my controller
public function ajaxCall(){
return response(Post::all());
}
It looks like you get to the ajaxCall() method by using the route '/home', but with axios, you are hitting "/" which returns a view called Welcome. Maybe you need to change the path you use in axios to '/home'?
It might be late but maybe someone else is looking for the solution
I was also facing this in SPA using laravel and VUE.
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
SPA has this route, so whenever you write any other get route your app will redirect you to the home page, to avoid this either move this route at the end of your web.php
or write your other routes in api.php file.
In my case i solved it by changing the GET method to POST method.
Try that. It might help

Axios sends POSITION instead of ID to the controller on delete

Im new to vue js, I found it a bit confusing in some parts but here is the latest confusion I am facing.
for example, I want to delete a row with the id of 3 but its position in the list is 0, when hitting delete it returns error in the console:
DELETE http://simvuecore/api/contoh/0 404 (Not Found)
which means axios sends the position while the controller expect ideven though id is actually not stated there.
for a refference, here are my codes:
API routes:
Route::delete('/contoh/{contoh}', 'contohController#destroy');
contohController:
public function destroy(contoh $contoh)
{
$contoh->delete();
return response('terhapus', 200);
}
store.js:
state: {
contoh: []
},
mutations: {
deleteContoh(state, id) {
const index = state.contoh.findIndex(item => item.id == id)
state.contoh.splice(index, 1)
}
},
actions: {
deleteContoh(context, id) {
axios.delete('api/contoh/' + id)
.then(response => {
context.commit('deleteContoh', id)
})
},
}
contohItem.vue:
methods: {
removeContoh(id) {
this.$store.dispatch('deleteContoh', id)
},
all CRUD operations work properly when using POSTMAN and when requested from vue, delete is the only one that doesn't work because of this position and id issue.
QUESTION:
how to tell axios to send id instead of position to the controller?
UPDATE:
Problem solved by following #andrey popov's answer.
I had this in contohItem.vue:
<span #click="removeContoh(index)" class="remove-contoh">X</span>
and it works after i changed it to this:
<span #click="removeContoh(id)" class="remove-contoh">X</span>
From your code I can see you're passing id all the way along the functions and deleteContoh action actually sends that to the server. Which means the way you call removeContoh is the problem - you're passing not id but index, and therefore you should change that.
Good luck!

Vue Router and Vuex

I have 2 questions.
1. How can I catch undefined routes and redirect to 404 page?
2. How I can use Vuex actions to get data from api? I know that vuex mutations must be sync and actions async. But I can get data with mutations and can use then promise. but can't in actions or I do anything mistake. Please give me beautiful example for that(component type). I use vuex in laravel mix in Laravel project. Thanks...
Generally speaking, you shouldn't be getting undefined routes if you're defining all of the routes within an app. You can define a redirect in your routes configuration as such:
[
{
path: 'admin/posts/list',
name: 'post-list',
},
{
path: 'admin/posts',
redirect: 'admin/posts/list'
}
]
// you can also redirect to a named route instead
// of a path like this:
{
path: 'admin/posts',
redirect: { name: 'post-list' }
}
If you wanted to do a "catch all" that grabs any paths not matched and redirect to your 404 component/view, then you could do it like this:
{
path: '*',
redirect: '/404'
}
Make sure that is at the bottom of your routes definition as the last route because it will catch any routes in the tree it is above.
As for your question about mutations/actions, asynchronous API requests like fetching data from an API only every happen within actions when you're using Vuex.Taken from the documentation on actions:
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}

Resources