fetch() with status code checking and re-routing In examples for fetch() I don't see many example for status code checking.

(1) I'm expecting to catch 403 unauthorised responses and push the login path to React router to render the login page. Haven't seen this elsewhere, but seems to work alright.

(2) Is it alright to nest the second .then the way I did or it should it somehow be outside the first .then?

loadData() {
    fetch(new UrlAssembler().template(this.props.endpoint).query(queryObject.get()).toString())
        .then(response =&gt; {
            if (response.status !== 200) {
                this.props.history.push( APP_LOGIN_PATH )
            } else {
                response.json().then(data =&gt;
                    this.setState({
                        data: data,
                        loaded: true,
                        isModalActive: false,
                        selectedElement: null,
                        selectedId: null,
                    }))
                }
        })
}
I don't see many example for status code checking


I think this way of thinking is a remnant of jQuery.ajax where anything not 2xx rejects the promise. On the other hand, fetch makes a request, and returns an object that represents the response. It's up to you and your app to decide what's a "correct" response from a "wrong" response.

Coming from an Angular background, the task of capturing 403s and doing redirects is the job of an HTTP interceptor service and not your component. This way, your component is not aware of this logic (it simply makes requests) and the behavior is applied globally on all your API calls. But since React doesn't have the same service structure, we'll make do with wrapping functions. 

So ideally, what your component should only ever contain is:

someWrappedVersionOfFetch(...)
  .then(response =&gt; response.json())
  .then(data =&gt; {
    this.setState({
      data: data,
      loaded: true,
      isModalActive: false,
      selectedElement: null,
      selectedId: null,
    }))
  })


Then the wrapped fetch would be like:

export const someWrappedVersionOfFetch = (...args) =&gt; {
  return fetch(...args)
    .then(response =&gt; {

      if (response.status !== 200) {
        // Update your history and reject the promise
        history.pushState( APP_LOGIN_PATH )
        return Promise.reject(response)
      } else {
        // Just pass response through.
        return Promise.resolve(response)
      }
    })
}


The above answers your first question. For your second question, you could do it like the second snippet. You put the conditional on the first then, have it conditionally return a resolved or rejected promise. Then just chain the one with setState after it.