My custom cache key isn't working in React Storefront

I’m using the out of the box React Storefront template and the custom cache key and cache optimization doesn’t seem to be working. My cache.js custom key looks like this:

const key = new CustomCacheKey().excludeAllQueryParametersExcept(
  'q',
  'sort',
  'filters',
  'color',
  'size',
  'amp'
).addCookie('userSegment');

module.exports = {
  FAR_FUTURE_TTL,
  PAGE_TTL,
  key,

  /**
   * The cache config for all server side rendered pages
   */
  SSR: {
    browser: {
      maxAgeSeconds: 0,
    },
    edge: {
      maxAgeSeconds: PAGE_TTL,
      staleWhileRevalidateSeconds: PAGE_TTL,
      key,
    },
  },

  /**
   * The cache config for all server side rendered pages
   */
  API: {
    browser: {
      maxAgeSeconds: 0,
      serviceWorkerSeconds: PAGE_TTL,
    },
    edge: {
      maxAgeSeconds: PAGE_TTL,
      staleWhileRevalidateSeconds: PAGE_TTL,
      key,
    },
  },

  /**
   * Cache config for static assets that never change and thus can be cached
   * at the edge and in the browser forever.
   */
  FAR_FUTURE: {
    browser: {
      maxAgeSeconds: FAR_FUTURE_TTL,
    },
    edge: {
      maxAgeSeconds: FAR_FUTURE_TTL,
      staleWhileRevalidateSeconds: 60 * 60 * 24,
    },
  },

  /**
   * Creates a route handler that caches based on the specified config
   * @param {Object} config A config for @xdn/core's cache function
   * @return {Function} a route handler
   */
  cacheResponse: config => ({ cache }) => cache(config),
}

The only modification I’ve made to the template is to add addCookie('userSegment') to the custom cache key. But when I try hitting my app via curl the x-xdn-t header shows a hit even when I try different values of the userSegment cookie.

For example, here’s a request with userSegment=foo and the returned x-xdn-t value shows oc=hit even though it was the first request with this cookie value.

ishananand@Ishan-Anand rsf-app-2020-12-09-1 % curl 'https://ishan-scratch-rsf-app-2020-12-09-1-default.moovweb-edge.io/' \
  -H 'Connection: keep-alive' \
  -H 'Cache-Control: max-age=0' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-Fetch-Mode: same-origin' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Accept-Language: en-US,en;q=0.9' \
  -H 'Cookie: userSegment=foo' \
  --compressed -o /dev/null -v 2>&1 | grep x-xdn-t
< x-xdn-t: ot=0,or=0,oc=hit,ow=114328

And I still get a hit if I immediately try another cookie value like bar:

ishananand@Ishan-Anand rsf-app-2020-12-09-1 % curl 'https://ishan-scratch-rsf-app-2020-12-09-1-default.moovweb-edge.io/' \
  -H 'Connection: keep-alive' \
  -H 'Cache-Control: max-age=0' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-Fetch-Mode: same-origin' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Accept-Language: en-US,en;q=0.9' \
  -H 'Cookie: userSegment=bar' \
  --compressed -o /dev/null -v 2>&1 | grep x-xdn-t
< x-xdn-t: ot=1,or=0,oc=hit,ow=114480
ishananand@Ishan-Anand rsf-app-2020-12-09-1 % 

Can you explain more what “doesn’t work” means in this case? What was the unexpected behavior? What did you do to produce it? What did you expect instead?

The problem is that the format of the key parameter moved in the XDN API and is no longer a parameter of the edge field. The React Storefront template in particular is still using the old format which no longer works.

In particular changing this (where key is a child of edge):

  SSR: {
    browser: {
      maxAgeSeconds: 0,
    },
    edge: {
      maxAgeSeconds: PAGE_TTL,
      staleWhileRevalidateSeconds: PAGE_TTL,
      key,
    },
  },

to this (where key is a peer to browser and edge):

  SSR: {
   key,
    browser: {
      maxAgeSeconds: 0,
    },
    edge: {
      maxAgeSeconds: PAGE_TTL,
      staleWhileRevalidateSeconds: PAGE_TTL,
    },
  },

fixes the problem.

We have logged tickets for React Storefront to update their template and to internally for the XDN to issue a warning if you have a project that uses the old format.