RxJS - Fetch

6 years ago

Using fetch with RxJS as a singular function, probably isn't terribly useful, but it becomes important later on when performing additional operations like transformations, debouncing, and projection.

Since fetch returns a promise, it is easy to wire up to RxJS's fromPromise (warning: official docs limited) and then subscribe.

The one thing to keep in mind is that fetch's initial response provides additional methods like json, blob, and text that result in promises as well. A simple pattern is to use a switchMap, and check for the response status. If the status is good, return you can then return an Observable from a promise based on one of the methods. Otherwise, throw an error with the response and handle it appropriately.

JavaScript (fetch.js)

const sample = {
  fetchUrl: isUrlInvalid => {
    const url = isUrlInvalid ? 'not-a-url' : 'https://dev-rest-api.herokuapp.com' + '/to-dos'
    const config = { method: 'GET' }

    const obs = Rx.Observable.fromPromise(fetch(url, config)).switchMap(response => {
      if (response.ok) {
        return Rx.Observable.fromPromise(response.json())
      } else {
        return Rx.Observable.throw(response)
      }
    })
    obs.subscribe(
      results => utility.updateResults('Next', JSON.stringify(results, null, 2)),
      error => utility.updateResults('Error', error.status + ' - ' + error.statusText),
      () => utility.updateResults('Complete')
    )
  },
  init: () => {
    sample.fetchUrl()
  }
}
const utility = {
  updateResults = (title, results) => {
    console.group()
    console.log(title)
    if(results) {
      console.log(results)
    }
    console.groupEnd()
  }
}

HTML (fetch.html)

<button onclick="sample.fetchUrl()" class="btn btn-success">Fetch</button>
<button onclick="sample.fetchUrl(true)" class="btn btn-danger">Fetch (Bad URL)</button>
<script>
  sample.init()
</script>

CDN Reference

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.min.js"
  integrity="sha256-hRKdKxNWF3kA5HoYA7GoSRILnmbQS4cwv23bJwqJlns=" crossorigin="anonymous"></script>


Discuss on Twitter