Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
34
rated 0 times [  37] [ 3]  / answers: 1 / hits: 17805  / 5 Years ago, tue, february 5, 2019, 12:00:00

I am currently working on a project to create a client for the Udemy instructor API.



I've written the client in Vue, using Axios as my HTTP client.



I have abstracted the different API requests into functions in an ES6-ified API wrapper library (Udemy.js) to allow them to be easily reused.



Udemy.js first initialises an instance of Axios, then exports API functions that use that instance as a base as promises.



Below is taken from the file, though I have removed all but one of the functions the module exports for ease of reading (and obviously redacted the API token). The endpoint URI contains message-threadssss — this is deliberate, to cause the server to return 404:





import axios from 'axios';

const token = '***************************';
const axiosOptions = {
baseURL: 'https://www.udemy.com/instructor-api/v1',
timeout: 10000,
headers: {
Accept: '*/*',
'Content-Type': 'application/json;charset=utf-8',
Authorization: `Bearer ${token}`,
},
};

const axiosInstance = axios.create(axiosOptions);

export default {
postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
})
.then(response => response.data)
.catch(error => error);
},
}







UdemyApi.postMessage(threadId, threadReply);
.then((response) => {
this.isLoading = false;
this.sentReply = response;
this.replyBody = '';
this.$root.$emit('reply-sent', {
threadId: this.thread.id,
sentReply: this.sentReply,
});
})
.catch((error) => {
if (error.response) {
// Case 1 (Server returned error)
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// Case 2 (Pre-response error)
console.log(error.request);
} else {
// Case 3 (Mysterious error)
console.log('Error:', error.message);
}
this.$root.$emit('show-snackbar', {
message: `Failed to send. ${error} `,
actionText: 'Understood. :(',
});
this.isLoading = false;
});





The request sends without a problem, and if the request is a success (i.e. 2xx), the Vue component is able to access the response data in the then() block.



When the server returns an error (404 in this instance), I would expect the caught error to contain a response object (Case 1).



Instead though, no response object is returned with the error (Case 2), which prevents me from handling it correctly. This happens when the request does cause the server to respond with a 404 error:



HTTP/2.0 404 Not Found
content-type: text/json


I've read that if Axios has interceptors applied to it, that can lead to this issue, but in this case, I've not applied any interceptors.



All in all, I'm at a bit of a loss. How do I get the server's response into my Vue component?



Edit (6th Feb)



I didn't include the all-useful console output in my initial post, so here it is. The console.log() line executed is the Case 2 line (just one console log entry is added, not prefixed with Error: , as would be the case in Case 3):



12:22:28.748
XMLHttpRequest
mozAnon: false
mozSystem: false
onabort: null
onerror: function handleError()
onload: null
onloadend: null
onloadstart: null
onprogress: null
onreadystatechange: function handleLoad()
ontimeout: function handleTimeout()
readyState: 4
response:
responseText:
responseType:
responseURL:
responseXML: null
status: 0
statusText:
timeout: 100000
upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
withCredentials: false
<prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }
replybox.vue:72


Edit 2 (6th Feb)



If I remove the then() and catch() from the postMessage() definition to look like this:



 postMessage(messageThreadId, messageBody) {
return axiosInstance
.post(`/message-threadssss/${messageThreadId}/messages/`, {
content: messageBody,
});
},


And then simplify the catch() block of the postMessage() call to just output the error object to look like this:



    .catch((error) => {
console.log(error);
this.$root.$emit('show-snackbar', {
message: `Failed to send. ${error} `,
actionText: 'Understood. :(',
});
this.isLoading = false;
});


The console outputs:



12:38:51.888 Error: Network Error
createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15
handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14
replybox.vue:62


Edit 3 (6th Jan)



I realised in my previous edit, I omitted the output of error.request after I'd removed .then and .catch from my postMessage definition. If I re-add console.log(error.request); to the .catch block of the call in my component, this is the output:



12:58:55.436
XMLHttpRequest
mozAnon: false
mozSystem: false
onabort: null
onerror: function handleError()
onload: null
onloadend: null
onloadstart: null
onprogress: null
onreadystatechange: function handleLoad()
ontimeout: function handleTimeout()
readyState: 4
response:
responseText:
responseType:
responseURL:
responseXML: null
status: 0
statusText:
timeout: 100000
upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
withCredentials: false
<prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }


Edit 4 (6th Feb)



To confirm or rule out my implementation of my API abstraction layer, I directly invoked an Axios instance in my component:



const token = '*********************';
const axiosOptions = {
baseURL: 'https://www.udemy.com/instructor-api/v1',
timeout: 100000,
headers: {
Accept: '*/*',
'Content-Type': 'application/json;charset=utf-8',
Authorization: `Bearer ${token}`,
},
};
const axiosInstance = axios.create(axiosOptions);
axiosInstance
.post(`/message-threadssss/${this.thread.id}/messages/`, {
content: this.replyBody,
})
.then((response) => {
this.isLoading = false;
this.sentReply = response;
this.replyBody = '';
this.$root.$emit('reply-sent', {
threadId: this.thread.id,
sentReply: this.sentReply,
});
})
.catch((error) => {
console.log('Error obj: ', error);
console.log('Request error obj: ', error.request);
this.$root.$emit('show-snackbar', {
message: `Failed to send. ${error} `,
actionText: 'Understood. :(',
});
this.isLoading = false;
this.axiosResult = error;
});


As before, the server returned the expected 404, and the .catch block in my component caught the error.



As before though, the response was missing from the caught error



13:25:45.783 Error obj:  Error: Network Error
createError webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15
handleError webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:87:14
replybox.vue:79

13:25:45.786 Request error obj:
XMLHttpRequest
mozAnon: false
mozSystem: false
onabort: null
onerror: function handleError()
onload: null
onloadend: null
onloadstart: null
onprogress: null
onreadystatechange: function handleLoad()
ontimeout: function handleTimeout()
readyState: 4
response:
responseText:
responseType:
responseURL:
responseXML: null
status: 0
statusText:
timeout: 100000
upload: XMLHttpRequestUpload { onloadstart: null, onprogress: null, onabort: null, … }
withCredentials: false
<prototype>: XMLHttpRequestPrototype { open: open(), setRequestHeader: setRequestHeader(), send: send(), … }
replybox.vue:80

More From » vue.js

 Answers
87

So, the answer it seems was actually the result of the API I was calling not serving the correct CORS headers with error responses (so CORS was only allowed for 2xx responses).



Consequently, Axios was unable to access the response.



I'll need to work around a general ambiguous error for the moment, but solution going forwards lies with developers of the API serving CORS with both success and error responses.



Many thanks to Bergi for their help, which ultimately led me to the cause of the issue.


[#52649] Thursday, January 31, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
lamarmaximiliand

Total Points: 388
Total Questions: 104
Total Answers: 104

Location: Oman
Member since Fri, Dec 23, 2022
1 Year ago
;