Home > Mobile >  Preventing the saving of data if one fails on Promise.all - VueJS
Preventing the saving of data if one fails on Promise.all - VueJS

Time:05-20

I have two forms with data that needs to be saved using two separate post APIs. I am using Promise.all() to save all the data from these two forms at once and its working as it should. The code is as follows:

saveAll() {
        Promise.all([
            this.$axios.post('v1/dummy-api/one',
              this.saveFormOne()
            ),
            this.$axios.post('v1/dummy-api/two',
              this.saveFormTwo()
            )
          ])
          .then(() => {
            this.success = 'Added Successfully.';
          })
          .catch(error => {
            this.error = 'Error.';
          })
      },

The issue am trying to solve is I need to check if any of those two request fails and if it does then prevent/cancel the saving of the other one (which succeed) until all of them succeed. I've tried try/catch with no luck.

Any help will greatly appreciated!

CodePudding user response:

You need to use Axios AbortController (https://axios-http.com/docs/cancellation). Be wary though that cancelling a request might not necessarily guarantee that the POST has not already been properly executed. If you must not call the other endpoint if one fails, the easiest way would be to chain them and call one after another.

Anyway, a way to achieve this is shown underneath. Note that I needed to modify it a bit in order for it to be executable inside stackoverflow answer. You'd get a general idea from it, though.

function saveAll() {
    const cancel = new AbortController();
    Promise.all([
            axios.get('https://test-stackoverflow.free.beeceptor.com', {}, {
                signal: cancel.signal
            }).catch((e) => {
                cancel.abort();
                throw e;
            }),
            axios.get('https://thiswillfail.com/fail', {}, {
                signal: cancel.signal
            }).catch((e) => {
                console.log('second request has failed')
                cancel.abort();
                throw e;
            })
        ])
        .then(() => {
            alert('Added Successfully.');
        })
        .catch(error => {
            alert('Error.');
        })
}
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<button onclick="saveAll()">save all</button>

CodePudding user response:

async saveAll() { 
 const resp1 = await this.$axios.post('v1/dummy-api/one', this.saveFormOne())
 const resp2 = await this.$axios.post('v1/dummy-api/two', this.saveFormTwo())
}

I don't know if this can be solved

CodePudding user response:

Promise.all() is not what you need if you need to manage these API calls. You can do somethin similar to what 王超华 suggested, but with additional try/catch

async function saveAll() { 
  let first;
  try {
    first = await this.$axios.post('v1/dummy-api/one', this.saveFormOne())
  } catch (e) {
    console.log('first failed')
    return
  }
  console.log('first', first)

  const second = await this.$axios.post('v1/dummy-api/two', this.saveFormTwo())
  console.log('second', second)
}

Or if you want to use Promises

saveAll() {
      this.$axios.post('v1/dummy-api/one', this.saveFormOne())
      .then(() => this.$axios.post('v1/dummy-api/two', this.saveFormTwo())
      .then(() => this.success = 'Added Successfully.')
      .catch(error => this.error = 'Error.')
  }

CodePudding user response:

I'm not sure how you can send a request, but cancel it at the same time.
A request can fail at several points, if your thing is failing when the DB is trying to save the entity, you cannot really cancel it from the client-side (without sending another HTTP call).

Either send another HTTP call from your client to update the backend on the failed status or let the backend rollback what you've tried if it's not correct.

This question is asking how to solve an issue regarding the design of a system here. The solution is not on the frontend, but rather on the backend/implementation itself.

You need to figure out a way to:

  • communication between the actions done on separate backends (link them somehow via a middleware backend or alike)
  • make a validation on the client before sending the 2 HTTP calls (via a simulation or a client side validation)
  • put in place some rollbacks

The cleanest approach would be to use Promise.allSettled, with a param of something like a dry-run ala git regarding both endpoints (if available), that way you could simulate the execution and result of both (and prevent any network errors), then re-run the query on both side if the simulation was correct.

  • Related