简体   繁体   中英

Trying to get data an 'status' from fetch Promise

I am trying to make a generic Fetch method for my React project. The plan is to pass my fetch method a url, and some config data (method, header etc). And then return less technical data to my calling methods. I'd like to return the data from the api call, and the payload, which is json data.

return fetch(URL, config)
    .then((response) => {
      console.log('Fetch - Got response: ', response);
      return response;
    })
    .then((response) => {
      console.log('Json: ', response.status);
      const result = { data: response.json(), status: response.status };
      return result;
    })
    .catch((e) => {
      console.log(`An error has occured while calling the API. ${e}`);
      reject(e);
    });

This is my initial attempt, but I'm not quite sure what I'm doing.

my console log that logs 'response', contains the response from the API call:

body: (...)
bodyUsed: true
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:49487//api/xxx/yyy"

So the API call completes, and I get a 200 status.

The line:

console.log('Json: ', response.status);

return 200 as expected.

What I have been doing before is

return response.json()

And then my calling class gets the paylad, but no status. What I am trying to do is return my payload, AND the status.

So I attempted to change it to this:

  const result = { data: response.json(), status: response.status };
  return result;

But my calling app now sees:

data: Promise {<resolved>: Array(9)}
status: 200

I was expecting to get data: MyPayloadArray, status: 200

I think I'm misunderstanding promises here. (I'm quite green with them).

My data accessor that uses my Fetch method:

 static GetAll() {
    return new Promise((resolve, reject) => {
      const request = {
        method: 'GET',
        URL: `${Server.ApiURL}/api/admin/clients`,
      };

      fetchData(request)
        .then((result) => {
          console.log('GetAll sees response as ', result);
          resolve(result);
        })
        .catch((error) => {
          reject(new Error(error));
        });
    });
  }

I'm trying to call my data accessor class, like this:

componentDidMount() {
ClientDataAccessor.GetAll()
  .then((response) => {
    console.log('Got list!', response);
    this.setState({ clients: response, isLoading: false });
  })
  .catch((error) => {
    console.log('Got error on list screen', error);
  });

}

How can I get just the status, and the payload back to my DataAccesor class? I think I'm just screwing up the Promises... But not sure of the best pattern here.

I'm going UI class, onComponentDidMount -> DataAccessor.GetAll -> FetchData. I think I'm abusing the Promise somewhere.

The issue here is that response.json() returns another promise. You would have to resolve that promise object yourself and return the object you are looking for.

return fetch(URL, config)
.then((response) => {
  console.log('Fetch - Got response: ', response);
  return response;
})
.then((response) => 
   response.json()
   .then( (data) => { data, status: response.status } )
)
.catch((e) => {
  console.log(`An error has occured while calling the API. ${e}`);
  reject(e);
});

Very ugly...

Why not move it to async/await funtion? All browsers support it at this stage...

async myFetch(URL, config) {
   try {
      const response = await fetch(URL, config);
      console.log('Fetch - Got response:', response);

      const data = await response.json();
      console.log('Fetch - Got data:', data);

      return { data, status: response.status }
   }
   catch (e) {
      console.error(`An error has occured while calling the API. ${e}`);
      throw e;
   }
}

Just be aware, in both cases, that your function returns another promise.

I think you can solve your issue using Promise.resolve , chaining promise to obtain your result object:

...
.then(response => {
    var status = response.status;
    return Promise.resolve(response.json())
           .then(data => ({ data, status }))
})

The Promise.resolve can take a Promise as parameter and return a promise that will flatten the chain, so you can get the value of the json parse and work with it.

You need to further resolve res.json() to get the info. You can do something like this:

return fetch(URL, config)
    .then((response) => {
      console.log('Fetch - Got response: ', response);
      return response;
    })
    .then(response =>
      response.json().then(json => ({
        status: response.status,
        json
      })
    ))
    .then(({ status, json }) => {
      console.log({ status, json });
      return { data: json, status: status };
    })
    .catch((e) => {
      console.log(`An error has occured while calling the API. ${e}`);
      reject(e);
    });

The neat version of above could be:

return fetch(URL, config)
    .then(response => response.json()
      .then(json => ({ status: response.status, data: json }) )
    )

Note: Removed the reject(e) from inside of catch , because it is redundant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM