Fetch api - получение тела json для обоих блоков и блоков catch для отдельных кодов состояния
Я использую fetch api для получения URL, который может вернуть:
Ответ: status = 200, json body = {'user': 'abc', 'id': 1}
или же
Ответ: status = 400, json body = {'причина': 'некоторая причина'}
или же
Ответ: status = 400, json body = {'причина': 'какая-то другая причина'}
Я хочу сделать отдельную функцию request()
что я использую из различных частей моего кода следующим образом:
request('http://api.example.com/').then(
// status 200 comes here
data => // do something with data.id, data.user
).catch(
// status 400, 500 comes here
error => // here error.reason will give me further info, i also want to know whether status was 400 or 500 etc
)
Я не могу сделать разделение между 200 и 400 500 (я попытался, выдав ошибку). Когда я выбрасываю ошибку, мне все еще трудно извлечь тело JSON (использовать для error.reason).
Мой текущий код выглядит следующим образом:
import 'whatwg-fetch';
/**
* Requests a URL, returning a promise
*/
export default function request(url, options={}) {
console.log('sending api request, url = ' + url)
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then((data) => ({data}))
.catch((err) => ({err}));
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
function parseJSON(response) {
return response.json(); // json() is a promise itself
}
Я попытался решить эту проблему следующим образом, инвертировав порядок .then()
звонит, но не работает
export default function request(url, options) {
return fetch(url, options)
.then(parseJSON) // note that now first calling parseJSON to get not just JSON but also status.
.then(checkStatus) // i.e. Inverted order of the two functions from before
.then((data) => ({data}))
.catch((err) => ({err}));
}
function checkStatus({data, status}) {
if (status >= 200 && status < 300) {
return data;
}
else {
// const error = new Error(response.statusText);
const error = new Error("Something went wrong");
// error.response = response;
error.data = data;
throw error;
}
}
function parseJSON(response) {
let jsonBody
response.json().then(json => {
jsonBody = json // this does not help, i thought it will make jsonBody fill up, but seems its in a diff thread
})
return {
data: jsonBody,
status: response.status // my aim is to send a whole dict with status and data to send it to checkStatus, but this does not work
}
}
2 ответа
response.json()
возвращает асинхронный результат. Вы не возвращаете объект в parseJSON
изнутри .then()
прикован к response.json()
, Чтобы исправить эту проблему, вы можете вернуться response.json()
обещать в parseJSON
вызов и возврат объекта, содержащего data
а также status
изнутри .then()
прикован к response.json()
function parseJSON(response) {
return response.json().then(json => {
return {
data: json,
status: response.status
}
})
}
Вот немного другой подход: с помощью одной строки я создаю обещание, похожее на ответ, с помощью ok, status и json-as-object (не обещание), а затем я решаю, что делать с этим объектом. Обычно я отклоняю с ответом, если response.ok имеет значение false, в противном случае я разрешаю только с помощью данных json. Сетевые ошибки /json-parse-errors отклоняются как обычно.
fetch(url, options)
.then(r => r.json().then(json => ({ok: r.ok, status: r.status, json})))
.then( r => r.ok ? r.json: Promise.reject(r))