Tengo una API HTTP que devuelve datos JSON tanto en caso de éxito como de error.
Un ejemplo de falla se vería así:
~ ◆ http get http://localhost:5000/api/isbn/2266202022 HTTP/1.1 400 BAD REQUEST Content-Length: 171 Content-Type: application/json Server: TornadoServer/4.0 { "message": "There was an issue with at least some of the supplied values.", "payload": { "isbn": "Could not find match for ISBN." }, "type": "validation" }Lo que quiero lograr en mi código JavaScript es algo como esto:
fetch(url) .then((resp) => { if (resp.status >= 200 && resp.status < 300) { return resp.json(); } else { // This does not work, since the Promise returned by `json()` is never fulfilled return Promise.reject(resp.json()); } }) .catch((error) => { // Do something with the error object }// This does not work, since the Promise returned by `json()` is never fulfilled return Promise.reject(resp.json());
Bueno, la promesa de resp.json se cumplirá, solo que Promise.reject no la espera e inmediatamente la rechaza con una promesa .
Asumiré que prefieres hacer lo siguiente:
fetch(url).then((resp) => { let json = resp.json(); // there's always a body if (resp.status >= 200 && resp.status < 300) { return json; } else { return json.then(Promise.reject.bind(Promise)); } })(o, escrito explícitamente)
return json.then(err => {throw err;});Aquí hay un enfoque algo más limpio que se basa en response.ok y hace uso de los datos JSON subyacentes en lugar de la Promise devuelta por .json() .
function myFetchWrapper(url) { return fetch(url).then(response => { return response.json().then(json => { return response.ok ? json : Promise.reject(json); }); }); } // This should trigger the .then() with the JSON response, // since the response is an HTTP 200. myFetchWrapper('http://api.openweathermap.org/data/2.5/weather?q=Brooklyn,NY').then(console.log.bind(console)); // This should trigger the .catch() with the JSON response, // since the response is an HTTP 400. myFetchWrapper('https://content.googleapis.com/youtube/v3/search').catch(console.warn.bind(console));La solución anterior de Jeff Posnick es mi forma favorita de hacerlo, pero el anidamiento es bastante feo.
Con la nueva sintaxis async/await , podemos hacerlo de una forma más sincrónica, sin el feo anidamiento que puede volverse confuso rápidamente.
async function myFetchWrapper(url) { const response = await fetch(url); const json = await response.json(); return response.ok ? json : Promise.reject(json); }Esto funciona porque una función asíncrona siempre devuelve una promesa y una vez que tenemos el JSON, podemos decidir cómo devolverlo según el estado de la respuesta (usando response.ok ).
Manejaría el error de la misma manera que lo haría en la respuesta de Jeff, sin embargo, también podría usar try/catch, una función de manejo de errores de orden superior , o con alguna modificación para evitar que se rechace la promesa, puede usar mi técnica favorita que asegura que el manejo de errores es se aplica como parte de la experiencia del desarrollador .
const url = 'http://api.openweathermap.org/data/2.5/weather?q=Brooklyn,NY' // Example with Promises myFetchWrapper(url) .then((res) => ...) .catch((err) => ...); // Example with try/catch (presuming wrapped in an async function) try { const data = await myFetchWrapper(url); ... } catch (err) { throw new Error(err.message); }También vale la pena leer MDN: verificar que la recuperación fue exitosa por qué tenemos que hacer esto, esencialmente una solicitud de recuperación solo se rechaza con errores de red, obtener un 404 no es un error de red.