Using fetch() and a new Promise object to get API results I've written an ES6 function using the new fetch() API and returning a new resolved promise with a data object or a rejected promise with an error subclass.

I'm pretty new to both ES6 and Promises, and it looks a little unwieldy, so I'm wondering if there's a better way. I'm also wondering about how this relates to the "explicit promise construction antipattern".

Any suggestions for how to improve or simplify?



function get(url) {
  console.log('Making fetch() request to: ' + url);

  let promise = new Promise((resolve, reject) =&gt; {
    fetch(url).then(response =&gt; {
      if (response.ok) {
        const contentType = response.headers.get('Content-Type') || '';

        if (contentType.includes('application/json')) {
          response.json().then(obj =&gt; {
            resolve(obj);
          }, error =&gt; {
            reject(new ResponseError('Invalid JSON: ' + error.message));
          });
        } else if (contentType.includes('text/html')) {
          response.text().then(html =&gt; {
            resolve({
              page_type: 'generic',
              html: html
            });
          }, error =&gt; {
            reject(new ResponseError('HTML error: ' + error.message));
          });
        } else {
          reject(new ResponseError('Invalid content type: ' + contentType));
        }
      } else {
        if (response.status == 404) {
          reject(new NotFoundError('Page not found: ' + url));
        } else {
          reject(new HttpError('HTTP error: ' + response.status));
        }
      }
    }, error =&gt; {
      reject(new NetworkError(error.message));
    });
  });

  return promise;
}
A few comments:

1) fetch already returns a promise, which means this:

new Promise((resolve, reject) =&gt; {
  return fetch(url).then(response =&gt; {
    if (response.ok) {
      resolve(response)
    } else {
      reject(new Error('error'))
    }
  }, error =&gt; {
    reject(new Error(error.message))
  })
})


Is pretty much the same as:

fetch(url).then(response =&gt; {
  if (response.ok) {
    return response
  }
  return Promise.reject(Error('error'))
}).catch(error =&gt; {
  return Promise.reject(Error(error.message))
})


2) Keeping this in mind you can simplify your code with early returns and fewer branches:

function get(url) {
  return fetch(url).then(response =&gt; {
    if (response.ok) {
      const contentType = response.headers.get('Content-Type') || '';

      if (contentType.includes('application/json')) {
        return response.json().catch(error =&gt; {
          return Promise.reject(new ResponseError('Invalid JSON: ' + error.message));
        });
      }

      if (contentType.includes('text/html')) {
        return response.text().then(html =&gt; {
          return {
            page_type: 'generic',
            html: html
          };
        }).catch(error =&gt; {
          return Promise.reject(new ResponseError('HTML error: ' + error.message));
        })
      }

      return Promise.reject(new ResponseError('Invalid content type: ' + contentType));
    }

    if (response.status == 404) {
      return Promise.reject(new NotFoundError('Page not found: ' + url));
    }

    return Promise.reject(new HttpError('HTTP error: ' + response.status));
  }).catch(error =&gt; {
    return Promise.reject(new NetworkError(error.message));
  });
}