39

Can anyone suggest any ways to get response times from Axios? I've found axios-timing but I don't really like it (controversial, I know). I'm just wondering if anyone else has found some good ways to log response times.

rozza
  • 927
  • 2
  • 11
  • 24

8 Answers8

61

You can use the interceptor concept of axios.

Request interceptor will set startTime

axios.interceptors.request.use(function (config) {
 
  config.metadata = { startTime: new Date()}
  return config;
}, function (error) {
  return Promise.reject(error);
});

Response interceptor will set endTime & calculate the duration

axios.interceptors.response.use(function (response) {
 
  response.config.metadata.endTime = new Date()
  response.duration = response.config.metadata.endTime - response.config.metadata.startTime
  return response;
}, function (error) {
  error.config.metadata.endTime = new Date();
  error.duration = error.config.metadata.endTime - error.config.metadata.startTime;
  return Promise.reject(error);
});
Artur Carvalho
  • 6,901
  • 10
  • 76
  • 105
Sagar M
  • 972
  • 8
  • 13
  • Are we allowed to add random stuff to config? – TA3 Aug 01 '18 at 06:18
  • I think, you have bug. When you try to get arrays of urls time add to previews and dont reset. SO last response calculate from first response time – Anton Skybun Sep 18 '19 at 08:58
  • 1
    If you mis-configure axios, you get an error but it doesn't have `error.config` so the error side of this need to check `if (error.config) {` before setting the endTime or duration. – Loren Dec 02 '19 at 16:13
  • 5
    I'm seeing an error: `Property 'metadata' does not exist on type 'AxiosRequestConfig'.` – patrick-fitzgerald Jan 23 '20 at 18:34
  • 3
    If you get an error "Property 'metadata' does not exist on type ..." that means you're using Typescript and `metadata` really doesn't exist for interface `AxiosRequestConfig`. You can define a new interface that will extend `AxiosRequestConfig` and cast config to it like `(config as YourInterfaceWithMeta).metadata` – Darkzarich Jul 23 '21 at 10:21
  • @patrick-fitzgerald, Are you setting the 'config.metadata' first? – Sagar M Jul 31 '21 at 13:46
  • @patrick-fitzgerald. One more solution in Typescript. instead of `config.metadata` you can use `config.data.metadata`. in this case you don't need to define new interface as @DarkZ suggested, because `data: any` – Roman Kazanovskyi Feb 18 '22 at 11:28
23

This is my solution, by setting the header in the interceptor:

import axios from 'axios'

const url = 'https://example.com'

const instance = axios.create()

instance.interceptors.request.use((config) => {
    config.headers['request-startTime'] = process.hrtime()
    return config
})

instance.interceptors.response.use((response) => {
    const start = response.config.headers['request-startTime']
    const end = process.hrtime(start)
    const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000))
    response.headers['request-duration'] = milliseconds
    return response
})

instance.get(url).then((response) => {
    console.log(response.headers['request-duration'])
}).catch((error) => {
    console.error(`Error`)
})
patrick-fitzgerald
  • 2,561
  • 3
  • 35
  • 49
7

Here's another way to do it:

const instance = axios.create() 

instance.interceptors.request.use((config) => {
  config.headers['request-startTime'] = new Date().getTime();
  return config
})

instance.interceptors.response.use((response) => {
  const currentTime = new Date().getTime()      
  const startTime = response.config.headers['request-startTime']      
  response.headers['request-duration'] = currentTime - startTime      
  return response
})

instance.get('https://example.com')
  .then((response) => {      
    console.log(response.headers['request-duration'])
  }).catch((error) => {
    console.error(`Error`)
  }) 
Wilson Chew
  • 81
  • 1
  • 3
4

easy way do this with async \ await, but not ideal :

const start = Date.now()
await axios.get(url)
const finish = Date.now()

const time = (finish - start) / 1000

This would be time about of axios call. Not so ideal, but showing and easy to implement

sergey_s
  • 119
  • 2
  • 6
3

piggybacking off of @user3653268- I modified their answer to use with react hooks and display x.xxx seconds using a modulo.

import React, { useState } from 'react';
import axios from 'axios';

export default function Main() {
  const [axiosTimer, setAxiosTimer] = useState('');

  const handleSubmit = () => {
      let startTime = Date.now();
      axios.post('urlstuff')
      .then(response => {
          console.log('handleSubmit response: ', response);
          axiosTimerFunc(startTime);
      })
      .catch(err => {
          console.log("handleSubmit error:", err.response.data.message)
          axiosTimerFunc(startTime);
          setLoading(false);
      });
    }

  const axiosTimerFunc = (startTime) => {
    let now = Date.now();
    let seconds = Math.floor((now - startTime)/1000);
    let milliseconds = Math.floor((now - startTime)%1000);
    setAxiosTimer(`${seconds}.${milliseconds} seconds`);
  }

  return(
     <div>
        <h2>Load Time: {axiosTimer}</h2>
     </div>
  )
}
jm2020
  • 31
  • 1
1

Another simple way to do it :

axios.interceptors.response.use(
  (response) => {
    console.timeEnd(response.config.url);
    return response;
  },
  (error) => {
    console.timeEnd(error.response.config.url); 
    return Promise.reject(error);
  }
);

axios.interceptors.request.use(
  function (config) {
    console.time(config.url );
    return config;
}, function (error) {
    return Promise.reject(error);
});
Yassine CHABLI
  • 3,459
  • 2
  • 23
  • 43
  • 2
    Until you have two simultaneous requests for the same URL (possibly even different HTTP methods). – Kir Oct 26 '21 at 19:35
0

Its way long after but this is my simple workaround

function performSearch() {
        var start = Date.now();
        var url='http://example.com';
        var query='hello';
        axios.post(url,{'par1':query})
            .then(function (res) {
                var millis = Date.now() - start;
                $('.timer').html(""+Math.floor(millis/1000)+"s")
            })
            .catch(function (res) {
                console.log(res)
            })


    }

this is my workaround

DenoGeek
  • 39
  • 1
  • 2
-1

actually you can get it through the "x-response-time" header that you get from the response on the axios request

axios({
          method: 'GET',
          url: 'something.com',

        })
          .then((response) => {
            console.log(response.headers['x-response-time']);
          })
AhmedReda
  • 9
  • 1