The .json method returns a promise, not the parsed value itself. If you want to access both the response and the parsed value in the same callback, you'll need to use nested functions like this:
fetch(url).then(response => { response.json().then(parsedValue => { // code that can access both here }) });
Alternatively, you can use await inside an asynchronous function to eliminate the need for callbacks.
const response = await fetch(url); const parsedValue = await response.json(); // code that can access both here
Of course, you'll want to check for errors, either with a .catch(...) call on a Promise or with a try...catch block in an async function. You could make a function that handles JSON and error cases, and then reuse it for all fetches. For example, something like this:
function handle(response) { if (response.ok) { return response.json().then(parsedValue => { // the status was ok and the body could be parsed return { response, parsedValue }; }).catch(err => { // the status was ok but the body was empty or not JSON return { response }; }); } else { return response.json().catch(err => { // the status was not ok and the body was not JSON throw new Error(response.statusText); }).then(parsedValue => { // the status was not ok and the body was JSON throw new Error(parsedValue.error); // assuming our API returns an object with an error property }); } }
I don't think it's the best design pattern, but hopefully this clarifies how the fetch API works. Note that the call to fetch itself can throw an error if something prevents the request from being sent in the first place.
PS: I avoided naming any variable or property json since that is the name of the text format. Once it's been parsed, it is no longer JSON. You might want to use a more meaningful name than parsedValue.
responsewill contain the promise that.json()returns, rather than the parsed payload of the response.