Open rafaelalmeidatk opened 4 years ago
since this solutions works, It should also be possible to be done inside httpAdapter.
// lib/adapters/http.js
module.exports = function httpAdapter(config){
const { stack: stackTrace } = new Error();
// outside the new Promise
config.stackTrace = stackTrace;
// or use some symbols or _stackTrace if it needs to be hidden.
return new Promise((function dispatchHttpRequest(resolvePromise, rejectPromise) {
....// long codes
})
}
// lib/core/enhanceError.js
module.exports = function enhanceError(error, config, code, request, response) {
error.config = config;
if (code) {
error.code = code;
}
error.request = request;
error.response = response;
error.isAxiosError = true;
error.stack = `${error.stack}${config.stackTrace}`;
....
how about it?
this is my sample code:
import axios, { AxiosInstance } from 'axios';
async function main(): Promise<void> {
const url = 'https://example.com/test';
const data = await axios.get(url).catch((error: Error) => {
console.error(error);
});
}
if (process.argv[1] === __filename) {
main();
}
and the console output:
Error: Request failed with status code 404
at createError (/Users/Ramadoka/development/side/ts/playground/node_modules/axios/lib/core/createError.js:16:15)
at settle (/Users/Ramadoka/development/side/ts/playground/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/Users/Ramadoka/development/side/ts/playground/node_modules/axios/lib/adapters/http.js:239:11)
at IncomingMessage.emit (events.js:208:15)
at IncomingMessage.EventEmitter.emit (domain.js:476:20)
at endReadableNT (_stream_readable.js:1168:12)
at processTicksAndRejections (internal/process/task_queues.js:77:11)Error:
at httpAdapter (/Users/Ramadoka/development/side/ts/playground/node_modules/axios/lib/adapters/http.js:20:33)
at dispatchRequest (/Users/Ramadoka/development/side/ts/playground/node_modules/axios/lib/core/dispatchRequest.js:59:10)
at processTicksAndRejections (internal/process/task_queues.js:85:5)
at main (/Users/Ramadoka/development/side/ts/playground/src/fetch.ts:5:16) { // <- the caller
config: {
url: 'https://example.com/test',
method: 'get',
... // more stuffs ...
}
Oh, I just realized that axios provided an adapter parameters inside the AxiosRequestConfig. so, you can do it in userland like this:
import axios, { AxiosRequestConfig, AxiosAdapter, AxiosPromise } from 'axios';
const httpAdapter: AxiosAdapter = require('axios/lib/adapters/http');
function customAdapter(config: AxiosRequestConfig): AxiosPromise<any> {
const { stack: stackTrace } = new Error();
return httpAdapter(config).catch((error) => {
error.stack = `${error.stack}${stackTrace}`;
throw error;
});
}
async function main(): Promise<void> {
const i = axios.create({ adapter: customAdapter });
const resp = await i.get('https://api.cryptoket.io/test').catch((error) => {
console.error(error);
});
}
if (process.argv[1] === __filename) {
main().catch(() => {});
}
Axios has some issues with errors, and it is even worse on SSR since the only thing you get when accessing the page is something like this:
Which is not useful at all, look at this stack trace! We have no clue where the request was done, how can we fix this? We have some issues like axios/axios#2387 and axios/axios#2069 but they don't have any solutions, so we need to solve this ourselves.
First of all, it is very advised to have a module to abstract axios and provide functions for each operation, so I will consider you have a
get
function that is similar to this:My first attempt was this:
But turns out even my error can't maintain the stack trace, this is happening because the function is called asynchronously, so the old stack trace is already lost. The trick here is to maintain the old stack trace before throwing the error, and I learned something:
Since it is just a string, we can store it before doing the request, and assign it to the error before throwing it:
And now our error contains the old stack trace, so we know exactly where the code has been called! To improve the current code we can move our catch function to somewhere else and output the response body in the error message, this is the full code:
And to use it:
I also moved the stack trace code into another function to repeat it in the other methods and I am manipulating it to remove the
getStackTrace
function from the stack trace, you can tweak it as you like: