2015-04-06 7 views
43

Ho un'API HTTP che restituisce i dati JSON sia in caso di esito positivo che in caso di errore.recupero: Rifiuta promessa con oggetto errore JSON

Un fallimento esempio sarebbe simile a questa:

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

Quello che voglio raggiungere nel mio codice JavaScript è qualcosa di simile:

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

Vuoi dire 'metodo json' restituisce un' Promise'? – thefourtheye

+2

Sì, secondo la specifica 'fetch' del gruppo di lavoro: https://fetch.spec.whatwg.org/#concept-body-consume-body – jbaiter

risposta

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

Ebbene, il resp.json promessa volontà essere soddisfatto, solo Promise.reject non lo attende e rifiuta immediatamente con una promessa.

darò per scontato che tu invece desidera effettuare le seguenti operazioni:

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, scritto in modo esplicito)

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

Grazie, (quasi) ha funzionato! Ho dovuto racchiudere Promise.reject in una funzione anonima o otterrei un errore 'indefinito non è una funzione ', ma con quel piccolo cambiamento funziona :-) – jbaiter

+0

Uh, stai pigro-caricando uno shim Promise? Il "Promise.reject" nativo non dovrebbe mai essere "indefinito". – Bergi

+0

Lo spessore viene caricato all'avvio dell'applicazione, quindi non deve essere caricato in modo pigro. Posso anche accedere a 'Promise.reject' bene dal debugger. Ecco la traccia completa: 'TypeError: undefined non è una funzione {stack:" TypeError: undefined non è una funzione↵ a reject (nativo) ", messaggio:" undefined non è una funzione "}' – jbaiter

26

Ecco un approccio un po 'più pulito che si basa su response.ok e si avvale di i dati JSON sottostanti anziché Promise restituiti da .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' sembra interessante, ma non vedo l'uso di" i dati JSON sottostanti "è più pulito.Dopo tutto, si potrebbe semplificare a' fetch (url) .then (response = > response.ok? response.json(): response.json(). then (err => Promise.reject (err))) ' – Bergi

+0

Intendo dire che invece di' let json = resp.json(); 'dove' json' è un 'Promise', potrebbe essere più semplice risolvere prima il' Promise' e ​​poi usare i dati con cui è stato risolto. O approccio funziona. –

+0

Stava cercando di rifiutare la promessa nidificata ma non era abbastanza sicuro di come. È venuto fuori che è semplicemente una chiamata al metodo di "rifiuto" statico, una risposta molto migliore di quella accettata a mio avviso. – Andris