2
0

Client-Side Request Deduplicator Help (Solved)

25d 23h ago by lemmy.world/u/tapdattl in javascript@programming.dev

Solved So turns out I need to store the original response and return clones. I've updated the code below to reflect that change. But feel free to use the below to deduplicate requests.

Hello,

I'm working on a small class to deduplicate API request calls. The basic function being a map of request path -> request promise. The issue I am running into is that on sequential calls I get a "response body has already been consumed" error.

From what I've read, I need to use response: (await res).clone() in the call to this.queryMap.set, however when I do that the map doesn't get updated in time to cache the calls (I think) and all 10 queries get sent to the API endpoint without being cached.

Any ideas on what I need to do?

class Deduplicator {
    queryMap = null;

    constructor() {
        this.queryMap = new Map();
    }

    async get(query, ttl = 10) {
        let now = Temporal.Now.instant();
        let cacheCheck = this.queryMap.get(query);
        if (cacheCheck == undefined || now.since(Temporal.Instant.from(cacheCheck.at)).seconds > ttl) {
            console.log("Cache miss on ", query)
            const res = fetch(query, {
                method: "GET",
            });
            this.queryMap.set(query, {
                at: now,
                response: res,
            })
            return (await res).clone(); //Previously just returned res
        } else {
            console.log("Cached response of ", query);
            return (await cacheCheck.response).clone(); //Previously just returned cacheCheck.response
        }
    }
}

Example:

let deduplicator = new Deduplicator();
for( let i = 0; i < 10; i++){
   let a = (await deduplicator.get("https://jsonplaceholder.typicode.com/todos/3", 10)).json();
   console.log('res: ', a);
}