angularrxjsangular-httpclient

How to execute angular http calls in order


I have to make a couple of optional calls to upload files to get ids before I can send a post to a different route with those file ids.

const body = ...

const updateFile1Reference = map((file: File | null) => {
  if (file) {
    body.file1 = { id: file.id }
  }
  return body
})

const uploadFile1 = body.file1 ?
  this.fileService.upload(body.file1).pipe(updateFile1Reference) :
  of(body)

const updateFile2Reference = map((file: File | null) => {
  if (file) {
    body.file2 = { id: file.id }
  }
  return body
})

const uploadFile2 = body.file2 ?
  this.fileService.upload(body.file2).pipe(updateFile2Reference) :
  of(body)

const update = this.service.update(body)

return of(body).pipe(
  switchMap(() => uploadFile1),
  switchMap(() => uploadFile2),
  switchMap(() => update)
)

However I am seeing the update run before the file uploads.


Solution

  • Reason for the issue:

    The switchMap in your code are running parallel; they are responsible for switching to the inner observable (uploadFile2, uploadFile1) from the outer observable (of(body)), they do not care if the previous switchMap completes or not. Thus we need to nest the switchMap operators for sequential execution.


    If you have APIs dependent on each other, then use forkJoin (to fetch the IDs in parallel), then use a nested switchMap to perform the final save.

    return forkJoin([uploadFile1, uploadFile2]).pipe(
      switchMap(() => update)
    )
    

    We can also reduce the boiler plate code by running a map operation and constructing the APIs.

    const files = ['file1', 'file2'];
    
    const api$: any[] = [];
    api$ = files.map((fileName: any) => body[fileName] ?
      this.fileService.upload(body[fileName]).pipe(
        map((file: File | null) => {
          if (file) {
            body[fileName] = { id: file.id }
          }
          return body
        })
     ) :
     of(body))
    
    return forkJoin(api$).pipe(
      switchMap(() => update)
    )