arthurfiorette / axios-cache-interceptor

📬 Small and efficient cache interceptor for axios. Etag, Cache-Control, TTL, HTTP headers and more!

Home Page:https://axios-cache-interceptor.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug: staleIfError + overrides don't seem to work on blocked requests

bperel opened this issue · comments

What happened?

I would like to mimic an offline mode behavior with axios-cache-interceptor.
If I understood the documentation properly, this can be done with a combination of overrides (I always want to retrieve the most recent data from the API) + staleIfError: true (if the user is offline, I want to failover to the cached version).

This is the sandbox that I tried it on:
https://codesandbox.io/s/stateiferror-n9kdr8

  • First, I click on the "Get" button. As expected, the data gets retrieved then cached.
  • Then, I block the request using Firefox developer tools:
Screenshot 2023-10-17 at 21 24 25

I would expect to see the message "custom predicate" in the console, but I don't, which seems to indicate that staleIfError doesn't work as I'm thinking it should. Am I doing something wrong?

axios-cache-interceptor version

v1.3.1

Node / Browser Version

Firefox 118

Axios Version

v1.5.1

What storage is being used

Web Storage

Relevant debugging log output

[{
  "id": "fetch-products",
  "msg": "Sending request, waiting for response",
  "data": {
    "overrideCache": false,
    "state": "empty"
  }
}, {
  "id": "fetch-products",
  "msg": "Useful response configuration found",
  "data": {
    "cacheConfig": {
      "update": {},
      "ttl": 300000,
      "methods": [
        "get",
        "head"
      ],
      "cachePredicate": {},
      "etag": true,
      "modifiedSince": false,
      "interpretHeader": true,
      "cacheTakeover": true,
      "override": false
    },
    "cacheResponse": {
      "data": {
        "products": [...],
        "total": 100,
        "skip": 0,
        "limit": 30
      },
      "status": 200,
      "statusText": "",
      "headers": {
        "content-type": "application/json; charset=utf-8",
        "x-axios-cache-stale-if-error": "300000"
      }
    }
  }
}, {
  "id": "fetch-products",
  "msg": "Found waiting deferred(s) and resolved them"
},{
  "id": "fetch-products",
  "msg": "Response cached",
  "data": {
    "cache": {
      "state": "cached",
      "ttl": 300000,
      "createdAt": 1697618799248,
      "data": {
        "data": {
          "products": [...],
          "total": 100,
          "skip": 0,
          "limit": 30
        },
        "status": 200,
        "statusText": "",
        "headers": {
          "content-type": "application/json; charset=utf-8",
          "x-axios-cache-stale-if-error": "300000"
        }
      }
    },
    "response": {
      "data": {
        "products": [...],
        "total": 100,
        "skip": 0,
        "limit": 30
      },
      "status": 200,
      "statusText": "",
      "headers": {
        "content-type": "application/json; charset=utf-8",
        "x-axios-cache-stale-if-error": "300000"
      },
      "config": {
        "transitional": {
          "silentJSONParsing": true,
          "forcedJSONParsing": true,
          "clarifyTimeoutError": false
        },
        "adapter": [
          "xhr",
          "http"
        ],
        "transformRequest": [
          null
        ],
        "transformResponse": [
          null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1,
        "env": {},
        "headers": {
          "Accept": "application/json, text/plain, */*",
          "Content-Type": null,
          "cache-control": "no-cache",
          "pragma": "no-cache",
          "expires": "0"
        },
        "baseURL": "https://dummyjson.com",
        "cache": {
          "update": {},
          "ttl": 300000,
          "methods": [
            "get",
            "head"
          ],
          "cachePredicate": {},
          "etag": true,
          "modifiedSince": false,
          "interpretHeader": true,
          "cacheTakeover": true,
          "override": false
        },
        "id": "fetch-products",
        "method": "get",
        "url": "/products"
      },
      "request": {},
      "id": "fetch-products",
      "cached": false
    }
  }
}, /* This is where I blocked the URL*/
{  
  "id": "fetch-products",
  "msg": "Returning cached response"
} , {
  "id": "fetch-products",
  "msg": "Returned cached response"
}]

Please attach debug logs

Please attach debug logs

Done

Your request is being sent to the network, then cached. Even if you block the request URL, subsequent request won't even reach your network tab in devtools because they are being cached at the javascript step.

Isn't this the correct behaviour? What should've been happening?

Since I assigned a function to the staleIfError option, I would expect that each time I make an axios request, this function is called since it's supposed to determine if the current request should return the existing cached response.
Moreover, since I specified override: true, I would expect the request to be made anyway since, if I understood the documentation properly, This option bypasses the current cache and always make a new http request.

@arthurfiorette Are my assumptions correct?

Hey @bperel. I simply tried out your reproducible example. After the first response is returned, it is put into the cache for subsequent requests. You blocking/unblocking a request won't have any effect until the cache expires.

As you can see in the debug logs:

{  
  "id": "fetch-products",
  "msg": "Returning cached response"
}
{
  "id": "fetch-products",
  "msg": "Returned cached response"
}

staleIfError, as the majority of other options, are only called if a request/cache revalidation is needed. While the request has fresh cache, it will not call staleIfError.

Actually, this exactly problem was a bug when applying override globally.

// does not work in v1.3.1
setupCache(axios, { override: true });
axios.get('url')
// works in v1.3.1
setupCache(axios);
axios.get('url', { cache: { override: true } })

Fixed in v1.3.2