Challenge 3: Diagnose a Cross-Request Cache Leak — Possible Solution ==================================================================== THE SETUP ---------- // Module-level singleton — created ONCE when the server starts, // shared by every request forever after. const sharedUserLoader = new DataLoader(async (ids) => { const users = await db.users.findByIds(ids); return ids.map((id) => users.find((u) => u.id === id)); }); // Every resolver, across every request, reads this same instance. Post: { author: (parent, args, context) => sharedUserLoader.load(parent.authorId), } WHAT GOES WRONG ----------------- DataLoader's cache is a plain in-memory map from ID to result, with absolutely no built-in concept of WHICH request or WHICH user a given cached entry belongs to — it only knows "I was asked to load ID 42 once already, here's what I got back last time." Because this instance is shared across every request rather than scoped to just one, that cache persists and accumulates across completely unrelated requests from completely different users, indefinitely (or until the process restarts). THE SPECIFIC DANGER IN AN APP WITH PER-USER DATA ACCESS RULES ------------------------------------------------------------------- Imagine a schema where a "user" object's visible fields depend on WHO is asking (e.g. an admin sees a user's email address, but an ordinary user viewing someone else's profile should not). If Admin's request loads and caches user ID 42 — including fields only an admin should see — and a completely different, non-admin User B's request later also happens to trigger sharedUserLoader.load(42) for some unrelated reason, DataLoader has no way to know this is a DIFFERENT request with DIFFERENT permissions. It simply returns the SAME cached object it already has for ID 42 — potentially handing User B data (or a data shape) that was only ever supposed to be visible to Admin, entirely because the cache doesn't know these were two separate, unrelated requests. Beyond the security angle, there's also a plain staleness problem: if User A updates their own name, and that update isn't reflected in the shared cache, every OTHER subsequent request across every other user might keep seeing the old, cached name indefinitely, since nothing ever tells this long-lived cache that the underlying data has changed. THE FIX -------- Create a brand-new DataLoader instance INSIDE whatever function builds the per-request context object (Chapter 3's fourth resolver parameter), so a fresh, empty cache exists for every single request and is discarded once that request finishes — exactly as this chapter's own createUserLoader() function is written to be called once per request, not once at server startup: function buildContextForRequest(req) { return { userLoader: createUserLoader(), // NEW instance, every request currentUser: req.user, }; } This guarantees no cached value can ever be seen by more than the one request that originally triggered it — completely eliminating both the cross-user leak and the indefinite staleness problem described above.