Home > Blockchain >  What would be a more efficient way to check for an error code in a `Response` body than using `clone
What would be a more efficient way to check for an error code in a `Response` body than using `clone

Time:12-06

Currently doing something like this in a Cloudflare worker

const response = await fetch(...);
const json = await response.clone().json<any>();
if (json.errorCode) {
  console.log(json.errorCode, json.message);
  return new Response('An error occurred', { status: 500 });
}

return response;

The service being proxied always returns a 200, so I have to check the presence of an errorCode field to know if it's an error. However the type of response is generally either a file or plaintext, not json. clone() seems to be the simplest solution to get access to the response while being allowed to return it still intact, but I'm wondering if there's a better way that's more memory efficient and can rely on the efficiency of streams. Haven't written node code in years so any help would be appreciated!

CodePudding user response:

Unfortunately, no, there's fundamentally nothing else you can do here. You have to read the whole message in order to JSON-parse it (even if you had a parser that could handle partial messages, you can't verify the absence of a field without reading the whole message). But since the status code is the first part of the response, you cannot stream the data back out to the client until you've decided the status code. So you have no choice but to buffer the entire response in memory.

With that said, practically speaking, the Workers Runtime doesn't like it when you do .clone() and only read from one branch. In fact, in the future this may stop working, by slowing down all branches to match the slowest-read branch. So, it may be better if you use .text() or .arrayBuffer() to read the whole body into memory, then JSON.parse() it, then construct a new response using the same headers and body to return to the client.

let text = await response.text();
let json = JSON.parse(text);
if (json.errorCode) {
  console.log(json.errorCode, json.message);
  return new Response('An error occurred', { status: 500 });
}
return new Response(text, response);

But that obviously uses just as much memory.

Maybe, as a heuristic, you could guess that a response doesn't contain an error if it's greater than a certain size? Since error messages are probably always relatively short? That would at least allow you to put a cap on the amount of buffering you need to do, though the code to implement this approach will be a bit complicated.

  • Related