Nuxt.js and handle API 404 response for dynamic pages - vue.js

I use Nuxt.js and I have dynamic page /items/{id}:
<template>
<div>
<h1>Item #{{ item.id }} «{{ item.title }}»</h1>
</div>
</template>
<script>
import { api } from '../../mo/api'
export default {
asyncData({ params }) {
return api(`items/${params.id}`)
},
}
</script>
Backend API returns object {item: {id: .., title: "...", ...}}.
But if an item with specified ID not exist API returns 404 response.
And Vue crash with "[Vue warn]: Property or method "item" is not defined on the instance but referenced during render."
How can I handle 404 response?
My api.js module:
import axios from 'axios'
export function api(url) {
url = encodeURIComponent(url)
return axios
.get(`http://localhost:4444/?url=${url}`)
.then(({ data }) => {
return data
})
.catch((err) => {
// 404 catch there
})
}
Solution:
Need to read manual: https://nuxtjs.org/guide/async-data/#handling-errors

just execute error function :)
<script>
export default {
asyncData({ params, error }) {
return axios
.get(`https://my-api/posts/${params.id}`)
.then((res) => {
return { title: res.data.title }
})
.catch((e) => {
error({ statusCode: 404, message: 'Post not found' })
})
},
}
</script>

If you're using the fetch() hook, this is how it should be written
<script>
export default {
async fetch() {
try {
await fetch('https://non-existent-website.commmm')
.then((response) => response.json())
} catch (error) {
this.$nuxt.context.error({
status: 500,
message: 'Something bad happened',
})
}
},
}
</script>
More context available here: https://nuxtjs.org/announcements/understanding-how-fetch-works-in-nuxt-2-12/#error-handling

Need to read the manual: https://nuxtjs.org/guide/async-data/#handling-errors :) .

Related

Calling API in method and getting [object Promise]

I'm using Nuxt.js in static site mode, and trying to get an image from an API using a string passed in a prop, however, in the template I am getting [object Promise]. I would've thought that return before the get request would resolve the promise, but I think my grasp of promises and Nuxt.js a little off. Any help would be greatly appreciated.
<template>
<div>
{{ getThumbnailSrc() }}
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
link: {
type: String,
required: true
}
},
data() {
return {
imageUrl: null
}
},
methods: {
getVimeoId(link) {
return link.split('/').pop()
},
getThumbnailSrc() {
return axios
.get(
`https://vimeo.com/api/v2/video/${this.getVimeoId(
this.link
)}.json`
)
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
return {
vimeoThumbnailUrl
}
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
It sure won't! XHR requests are asynchronous and therefore the template has no idea that it needs to wait.
Solve it by using an additional data property on the component, and using that instead:
data() {
return {
imageUrl: null,
thumbnailSrc: null
}
},
And in your callback:
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
this.thumbnailSrc = vimeoThumbnailUrl
})
Now you can use {{thumbnailSrc}} and it will load appropriately.

How to delete data using Vue.axios.delete()

I am new to vuejs. I am having trouble deleting json data from a fakeserve by using axios.delete().
I tried doing this :-
axios.delete('http://localhost:3000/users/', {params: {id: this.idToDelete} })
.then((response) => {
console.log(response)
}, (error) => {
console.log(error)
})
This is my html:-
<v-text-field v-model="idToDelete" type="number" hide-details outline
label="Enter Id to delete"></v-text-field>
<v-btn #click="userIdtoDelete()" color="error">Delete</v-btn>
This is my javascript (src/views/pages/Delete.vue):
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
export default {
data () {
return {
idToDelete: ''
}
},
methods: {
userIdtoDelete () {
axios.delete('http://localhost:3000/users/', {params: {id: this.idToDelete} })
.then((response) => {
console.log(response)
//alert('response = ' + response)
}, (error) => {
console.log(error)
//alert('error = ' + error)
})
}
}
}
My code is in https://github.com/boidurja/users.git
And fakeserver is in https://github.com/boidurja/fakeserver.git
When I click the delete button data is not getting deleted and I am getting the following error message:-
DELETE http://localhost:3000/users/?id=3 404 (Not Found)
JSON Server automatically creates routes in a RESTful format, eg
GET /users
GET /users/1
POST /users
PUT /users/1
PATCH /users/1
DELETE /users/1
So with that in mind, you should be using
axios.delete(`http://localhost:3000/users/${encodeURIComponent(this.idToDelete)}`)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
I think your issue is that you are calling a function inline with () vue does this for you, try
<v-btn #click="userIdtoDelete" color="error">Delete</v-btn>
I think you are triggering the function twice.
In addition, you can try instead of using v-model to catch the id directly in the function like userIdtoDelete($event.target.value)

How to use $nuxt.$loading from axios interceptor

I would like to use $nuxt.$loading https://nuxtjs.org/api/configuration-loading/ outside of Vue component. I created central js for hitting APIs.
services/api-client.js
import axios from "axios";
import { state } from '../store/modules/sessions';
const axiosClient = axios.create({
baseURL: process.env.BASE_URL,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Api-Key': state().token
}
});
axiosClient.interceptors.request.use(function (config) {
// show nuxt loading here
return config;
}, function (error) {
return Promise.reject(error);
});
axiosClient.interceptors.response.use(function (response) {
// hide nuxt loading here
if (response.data.status.code != 200) {
throw { message: response.data.status.errorDetail };
} else {
return response;
}
}, function (error) {
// hide nuxt loading here
return Promise.reject(error);
});
export default {
all(path) {
return axiosClient.get(path);
},
show(path) {
return this.all(path);
},
create(path, params) {
return axiosClient.post(path, params);
},
update(path, params) {
return axiosClient.put(path, params);
}
};
and from my index.vue I'm dispatching the actions which trigger the Api Request.
<template>
<div>
<h1> Welcome </h1>
</div>
</template>
<script>
export default {
created() {
this.$store.dispatch('getInsiders', this);
}
}
</script>
The solution to your problem is this code below.
Please try this.
export default function({ $axios, store }: any) {
$axios.onRequest((config: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.start()
return config
})
})
$axios.onResponse((response: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.finish()
return response
})
})
$axios.onError((error: any) => {
store._vm.$nextTick(() => {
store._vm.$nuxt.$loading.finish()
return Promise.reject(error)
})
})
}
Do you really need to declare own axios client?
Standard way how to do this is using nuxt's axios module and then customize it in your plugin.
nuxt.config.js
modules: ['#nuxtjs/axios'],
plugins: ['~/plugins/axios']
~/plugins/axios
export default ({ $axios, redirect }) => {
$axios.onError(error => {
// do anything you need
})
}
The axios module will manage loading status automatically.
Although you still can disable progress for individual requests
Eg from component/action
await this.$axios.$get('/myapi', { progress: false })

Cannot set property after Get reques - Axios and HTML5 datalist

I am trying to do a GET request using Axios , but get the following error in console:
TypeError: Cannot set property 'films' of undefined
at eval (SearchBar.vue?e266:26)
SearchBar.vue
<template>
<section>
<input v-model='film' type='text' list='films'>
<datalist id='films'>
<option v-for='film in films' :key='film.episode_id'>{{film}}</option>
</datalist>
</section>
</template>
<script>
import axios from "axios";
export default {
name: "SearchBar",
data() {
return {
film: "",
films: []
};
},
created() {
axios
.get("https://swapi.co/api/films/")
.then(function(response) {
// handle success
//console.log(response);
this.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
};
</script>
Anyone can tell me why I get the error? Note: I am running this locally for instant prototyping via Vue-Cli
One way is to use Arrow function:
created() {
axios
.get("https://swapi.co/api/films/")
.then((response) => {
// handle success
//console.log(response);
this.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
2. Another way that = this & then use that inside promise callback
created() {
const that = this; // <-- assign this in that
axios
.get("https://swapi.co/api/films/")
.then(function (response) {
// handle success
//console.log(response);
that.films = response.data.results;
})
.catch(function(error) {
// handle error
console.log(error);
});
}

Printing data variable

I am trying to print data() variable. I am not getting output in HTML template.
<template>
<h3>{{app_skills}}</h3> <!-- I am not getting value here -->
</template>
<script>
export default {
name: "leftbar",
data() {
return {
app_skills: '',
}
},
methods : {
fetchskills (url) {
url = '/skills';
axios.get(url)
.then(response => {
this.app_skills = response.data.skills;
console.log(this.app_skills) // I am getting value here
})
.catch(error => {
console.log(error);
});
}
},
mounted() {
this.fetchskills();
}
}
</script>
Your code worked exactly as expected when I tried it (with a few environment-related changes):
<template>
<h3>{{app_skills}}</h3> <!-- I am not getting value here -->
</template>
<script>
import axios from 'axios';
export default {
name: "leftbar",
data() {
return {
app_skills: '',
}
},
methods : {
fetchskills (url) {
url = 'https://dns.google.com/resolve?name=example.com';
axios.get(url)
.then(response => {
this.app_skills = response.data;
console.log(this.app_skills) // I am getting value here
})
.catch(error => {
console.log(error);
});
}
},
mounted() {
this.fetchskills();
}
}
</script>
All I changed was including the axios library, changing the URL to pull from, and changing the response.data key to pull. It all works as expected. Perhaps you have an issue somewhere else in your surrounding code?