Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to parse json after exception handling promise with isomorphic-fetch

During implementing login feature with React, Redux, isomorphic-fetch, ES6 Babel.

Questions

I do not know how to properly combine promises after the checkstatus promise in order to get parsed JSON data from my server.
what am I doing wrong here?

also, do I need to replace isomorphic-fetch package with other more convenient one?
any suggestion for other package is welcome!

loginAction.js

import * as API from '../middleware/api';
import * as ActionTypes from '../actionTypes/authActionTypes';
import 'isomorphic-fetch';

function encodeCredentials(id, pwd) {
  return btoa(`${id}{GS}${pwd}`);
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    response;
  } else {
    const error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}

function parseJSON(response) {
  return response.json();
}

export function loginFailure(error) {
  return { error, type: ActionTypes.LOGIN_FAILURE };
}

export function loginSuccess(response) {
  return dispatch => {
    dispatch({ response, type: ActionTypes.LOGIN_SUCCESS });
  };
}

export function loginRequest(id, pwd) {
  return {
    type: ActionTypes.LOGIN_REQUEST,
    command: 'login',
    lang: 'en',
    str: encodeCredentials(id, pwd),
    ip: '',
    device_id: '',
    install_ver: '',
  };
}


export function login(id, pwd) {
  const credentials = loginRequest(id, pwd);

  return dispatch => {
    fetch(`${API.ROOT_PATH}${API.END_POINT.LOGIN}`, {
      method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(credentials),
    })
    .then(checkStatus)
    .then(parseJSON)
    .then(data => {
      console.log(`parsed data ${data}`);
      dispatch(loginSuccess(data));
    })
    .catch(error => {
      console.log(`request failed ${error}`);
    });
  };

}
like image 719
seoyoochan Avatar asked Jan 13 '16 17:01

seoyoochan


People also ask

How use JSON after fetch?

To get JSON from the server using the Fetch API, you need to use the fetch() method. We need to use an additional call to the response. json() method to get the response body. The "Accept: application/json" header accepts the type of data the client wants to receive in the response.

Does fetch parse JSON?

When the fetch is successful, we read and parse the data using json() , then read values out of the resulting objects as you'd expect and insert them into list items to display our product data.

How do you deal with failed fetch?

The fetch() function will automatically throw an error for network errors but not for HTTP errors such as 4xx or 5xx responses. For HTTP errors we can check the response. ok property to see if the request failed and reject the promise ourselves by calling return Promise.

How do I get the fetch error code?

To get the status code of an HTTP request made with the fetch method, access the status property on the response object. The response. status property contains the HTTP status code of the response, e.g. 200 for a successful response or 500 for a server error.


2 Answers

In my projects usually, I have a helper function fetchJSON that does all utility logic, such as JSON parsing and status check.

Here it is:

import fetch from 'isomorphic-fetch';

function checkStatus(response) {
  if(response.ok) {
    return response;
  } else {
    const error = new Error(response.statusText);
    error.response = response;
    throw error;
  }
}

function parseJSON(response) {
  return response.json();
}

export default function enhancedFetch(url, options) {
  options.headers = Object.assign({
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }, options.headers);
  if(typeof options.body !== 'string') {
    options.body = JSON.stringify(options.body);
  }
  return fetch(url, options)
    .then(checkStatus)
    .then(parseJSON);
}

Then you can use it in actions:

import fetchJSON from '../utils/fetchJSON'; // this is the enhanced method from utilities

export function login(id, pwd) {
    const credentials = loginRequest(id, pwd);

    return dispatch => {
       fetchJSON(`${API.ROOT_PATH}${API.END_POINT.LOGIN}`, {
           method: 'post',
           body: credentials
       }).then(data => {
           console.log(`parsed data ${data}`);
           dispatch(loginSuccess(data));
       }).catch(error => {
           console.log(`request failed ${error}`);
       });
   };
}

It helps you to keep actions code clean from some boilerplate code. In big projects with tons of similar fetch calls it is a really must-have thing.

like image 176
just-boris Avatar answered Oct 06 '22 01:10

just-boris


You're doing it right, you just forgot return in checkstatus; you should return the response such that the next promise in the chain can consume it.

Also, it seems that checkstatus is synchronous operation, so it's no need to chain it by .then (although, it's OK if you like it that way), you can write:

fetch(...)
.then(response=>{
   checkStatus(response)
   return response.json()
})
.then(data=>{
   dispatch(loginSuccess(data))
})
.catch(...)

I see no reason to get rid of isomorphic-fetch for now - it seems that it does its job.

like image 37
Tomas Kulich Avatar answered Oct 05 '22 23:10

Tomas Kulich