68

Is this the only way to use the body.json() and also get the status code?

let status; return fetch(url) .then(response => { status = response.status; return response.json() }) .then(response => { return { response: response, status: status } }); 

This doesn't work as it returns a promise in the response field:

.then((response)=> {return {response: response.json(), status: response.status}}) 
2
  • What is wrong with return {'response': resp.json(), 'status': resp.status} ? Commented Nov 13, 2017 at 15:00
  • @NicoVanBelle response will contain the promise that .json() returns, rather than the parsed payload of the response. Commented Sep 27, 2023 at 13:24

5 Answers 5

135

Your status is not visible in the second then. You can just get the two properties in the single then.

json() returns a new Promise to you, so you need to create your object inside the then of the result of that function. If you return a Promise from a function, it will be fulfilled and will return the result of the fulfillment - in our case the object.

fetch("https://jsonplaceholder.typicode.com/posts/1") .then(r => r.json().then(data => ({status: r.status, body: data}))) .then(obj => console.log(obj));

Sign up to request clarification or add additional context in comments.

3 Comments

response.body is a ReadableStream. response.json is a method that returns a promise to an object.
@NikhilVJ Would you mind posting an equivalent ajax-only response ?
"Your status is not visible in the second then." → It is, though, thanks to being declared within the wider closure via let.
33

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.

2 Comments

Note: I have used a solution like this in production once, but it was for a small app calling a backend API I made myself. There are probably better patterns to follow if your use case isn't trivial.
Interesting patterns can be found here: danlevy.net/you-may-not-need-axios
15

Using two 'then's seem unnecessary to me.

async/await could get the job done pretty easily.

 fetch('http://test.com/getData') .then( async (response) => { // get json response here let data = await response.json(); if(data.status === 200){ // Process data here }else{ // Rest of status codes (400,500,303), can be handled here appropriately } }) .catch((err) => { console.log(err); }) 

1 Comment

I wouldn't mix async/await syntax with .then(...) syntax. If you're going to use await at all, then you should probably use const response = await fetch(...); as well.
1

The introduction of async and await makes it easy to handle data from dependant promises in one place.

Since it doesn't involve the use of callback functions, the variables all exist in the same scope.

const myFunction = async (url) => { const response = await fetch(url); const status = response.status; const data = await response.json(); return { data, status }; }; 

Comments

0

Did you try this?

return fetch(url) .then((r)=> {return {response: r.json(), status: r.status}}) 

3 Comments

I've tried. The problem is that r.json() is a promise and returning it like this means I get a promise in the response field.
than @Suren Srapyan is best solution I think
This will produce an object where response is a promise.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.