Search code examples
node.jsasync-awaitfetch

Sequence of 3 node fetch POST calls fails unless combining await and then


In a javascript I run the below 3 fetch POST requests:

test.js

fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b1
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});


fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b2
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});


fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b3
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});

but it randomly fails with one or two of the requests e.g.:

❯ node test.js
500
{
  type: 'https://httpstatuses.com/500',
  title: 'Internal Server Error',
  status: 500,
  detail: ''
}
500
{
  type: 'https://httpstatuses.com/500',
  title: 'Internal Server Error',
  status: 500,
  detail: ''
}
200
{
  status: 'succesful!'
}

But if I add an await to each fetch:

await fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b1
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});


await fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b2
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});


await fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: "Bearer " + token,
    "Content-Type": "application/json-patch+json",
    "accept": "application/json"  
  },
  body: b3
})
 .then((response) => {
  console.log(response.status)
  return response.json()
})
.then(data => {
  console.log(data);
})
.catch(error => {
  console.error('CREATE Error:', error);
});

it always works - all 3 get successfully posted:

❯ node test.js
200
{
  status: 'succesful!'
}
200
{
  status: 'succesful!'
}
200
{
  status: 'succesful!'
}

From what I understand you can combine await and then but generally you either select either the await approach or the then approach.

So what am I doing wrong in the above example?

How do I make all these 3 post request complete successfully each time with using only then?

Then I will deal with the doing it using just await only or Promise.all: https://vanillajstoolkit.com/reference/ajax/multiple-endpoints/

as a follow up exercise unless I of course need to use them combined with then.

UPDATE: And the example with curl that always works (probably because curl is synchronous/internally does waiting correctly):

bodies.forEach(body => {
  const cmd = `curl -si -X POST -H 'accept: application/json' \
  -H 'Content-Type: application/json-patch+json' \
  -H "Authorization: Bearer ${token}" \
  -d '${body}' '${endpoint}'`
  
  const execSync = child.execSync;
  const result = execSync(cmd, { encoding: "utf-8" });
  console.log(result)
}) 

when executed:

❯ node test_curl.js
HTTP/2 200
...

HTTP/2 200
...

HTTP/2 200
...

But "forcing" async invocations with curl based on this example: https://serverfault.com/a/1084693/138328

gives same unpredictable/random failing behaviour as when using fetch/then


Solution

  • In the comment-section of the question we have reached the conclusion that the server does not serve too frequent requests or on-going requests.

    This was experimentally verified via sending async cURL requests and the problem reproduced even then, which proves that the issue is not due to the fetch call per se, but to the asynchronous nature of parallelly sent requests.