2015-04-06 1 views
43

J'ai une API HTTP qui renvoie des données JSON à la fois en cas de succès et en cas d'échec.fetch: rejeter la promesse avec l'objet d'erreur JSON

Un échec exemple ressemblerait à ceci:

~ ◆ 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" 
} 

Ce que je veux réaliser dans mon code JavaScript est quelque chose comme ceci:

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 
    } 
+0

Vous voulez dire 'méthode json' retourne un' Promise'? – thefourtheye

+2

Oui, selon la spécification 'fetch' du groupe de travail: https://fetch.spec.whatwg.org/#concept-body-consume-body – jbaiter

Répondre

71
// This does not work, since the Promise returned by `json()` is never fulfilled 
return Promise.reject(resp.json()); 

Eh bien, la resp.json promesse sera être remplies, seulement Promise.reject n'attend pas et rejette immédiatement avec une promesse.

Je suppose que vous voulez plutôt faire ce qui suit:

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)); 
    } 
}) 

(ou, écrit explicitement)

return json.then(err => {throw err;}); 
+0

Merci, ça a (presque) marché! J'ai dû emballer Promise.reject dans une fonction anonyme ou j'obtiendrais une erreur 'non définie n'est pas une fonction', mais avec ce petit changement cela fonctionne :-) – jbaiter

+0

Euh, êtes-vous paresseux-chargement d'un shim Promise? Le 'Promise.reject 'natif ne devrait jamais être' undefined'. – Bergi

+0

Le shim est chargé au démarrage de l'application, il ne doit donc pas être chargé paresseux. Je peux aussi accéder à 'Promise.reject' depuis le débogueur. Voici la trace complète: 'TypeError: undefined n'est pas une fonction {pile:" TypeError: undefined n'est pas une fonction "à reject (native)", message: "undefined n'est pas une fonction"} ' – jbaiter

26

Voici une approche un peu plus propre qui repose sur response.ok et utilise les données JSON sous-jacentes au lieu du Promise renvoyé par .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));

+1

Ah, '.ok 'semble intéressant.Mais je ne vois pas l'utilisation de" les données JSON sous-jacentes "est plus propre.Après tout, vous pouvez simplifier cela à' fetch (url) .then (réponse = > response.ok? response.json(): réponse.json(). then (err => Promise.reject (err))) ' – Bergi

+0

Je voulais dire qu'à la place de' let json = resp.json(); 'où' json' est un 'Promise', il pourrait être plus simple de résoudre le' Promise' d'abord et ensuite utiliser les données avec lesquelles il a été résolu.Chaque approche fonctionne –

+0

Essayait de rejeter la promesse imbriquée mais n'était pas tout à fait sûr comment. Il s'avère que c'est simplement un appel à la méthode statique de "rejet", une meilleure réponse que celle acceptée à mon avis. – Andris