Skip to content

feat: implement etag on fetch entities actions#182

Open
tomrndom wants to merge 2 commits into
mainfrom
fix/fetch-entities-etag
Open

feat: implement etag on fetch entities actions#182
tomrndom wants to merge 2 commits into
mainfrom
fix/fetch-entities-etag

Conversation

@tomrndom

@tomrndom tomrndom commented Oct 9, 2025

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

  • Add ETag headers to fetch entities actions
  • Function to fetch with ETag and manage 304 errors

Does this PR introduce a breaking change?

No

What needs to be documented once your changes are merged?

Nothing

ref: https://app.clickup.com/t/86b70mfce

Signed-off-by: Tomás Castillo tcastilloboireau@gmail.com

@tomrndom tomrndom requested a review from smarcet October 9, 2025 22:55
@netlify

netlify Bot commented Oct 9, 2025

Copy link
Copy Markdown

Deploy Preview for qa-fnvirtual ready!

Name Link
🔨 Latest commit 25cf3bf
🔍 Latest deploy log https://app.netlify.com/projects/qa-fnvirtual/deploys/69ab2c08b38d9f000765b5b1
😎 Deploy Preview https://deploy-preview-182--qa-fnvirtual.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@smarcet smarcet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(See inline comments below)

@@ -3,6 +3,50 @@ import SummitAPIRequest from "../utils/build-json/SummitAPIRequest";
import EventAPIRequest from "../utils/build-json/EventsAPIRequest";
import SpeakersAPIRequest from "../utils/build-json/SpeakersAPIRequest";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

etagCache grows unbounded with no eviction strategy. In long,running sessions (conference attendees keeping tabs open for hours), this could consume significant memory.

Consider using a Map with a size limit:

const etagCache = new Map();
const MAX_CACHE_SIZE = 100;

// Before inserting:
if (etagCache.size >= MAX_CACHE_SIZE) {
  const oldest = etagCache.keys().next().value;
  etagCache.delete(oldest);
}

Comment thread src/actions/fetch-entities-actions.js Outdated

const byLowerCase = toFind => value => toLowerCase(value) === toFind;
const toLowerCase = value => value.toLowerCase();
const getKeys = headers => Object.keys(headers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These helper functions (byLowerCase, toLowerCase, getKeys, getHeaderCaseInsensitive) are unnecessary. The fetch Headers object is not a plain object, so Object.keys(headers) won't iterate it correctly.

Headers.get() is already case,insensitive by spec. You can replace all of this with:

const responseETAG = res.headers.get('etag');

This is simpler and actually correct.

const key = getKeys(headers).find(byLowerCase(headerName));
return key ? headers[key] : undefined;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ETag cache may conflict with the real,time updates system. When Ably pushes an update and the sync strategies call these fetch functions to get fresh data, the cached ETag could cause a 304 response, returning stale data instead of the updated entity.

Scenario:

  1. User loads summit → cached with ETag
  2. Backend updates summit → Ably message triggers synchEntityData
  3. fetchSummitById sends If,None,Match with old ETag
  4. Server responds 304 → stale cached data returned

Consider exporting a clearEtagCache function to invalidate entries when real,time updates are received:

export const clearEtagCacheForUrl = (urlPattern) => {
  for (const key of Object.keys(etagCache)) {
    if (key.includes(urlPattern)) {
      delete etagCache[key];
    }
  }
};

Then call it from sync strategies before re,fetching.

if (responseETAG) {
etagCache[cacheKey] = { etag: responseETAG, body: data };
}
return data;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non,200/304 status codes are silently swallowed here. If the server returns 401, 403, 404, or 500, the function just returns null with no indication of what went wrong.

Consider adding error logging:

if (!res.ok) {
  console.error(`fetchWithEtag failed (${res.status}):`, url);
}

return null;

Comment thread src/actions/fetch-entities-actions.js Outdated
}

const apiUrlWithParams = EventAPIRequest.build(apiUrl);
const cacheKey = apiUrlWithParams;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: cacheKey is always identical to apiUrlWithParams (same pattern repeats in every function below). Consider removing the cacheKey parameter from fetchWithEtag and just using the URL directly as the cache key inside the function. This would simplify all call sites from:

const cacheKey = apiUrlWithParams;
return fetchWithEtag(apiUrlWithParams, cacheKey);

To just:

return fetchWithEtag(apiUrlWithParams);

@smarcet smarcet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomrndom please review

tomrndom added 2 commits March 6, 2026 16:32
Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
…l time updates

Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
@tomrndom tomrndom force-pushed the fix/fetch-entities-etag branch from dfdeea3 to 25cf3bf Compare March 6, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants