Angular 2: How to access an HTTP response body?
Asked Answered
E

12

53

I wrote the following code in Angular 2:

this.http.request('http://thecatapi.com/api/images/get?format=html&results_per_page=10').
      subscribe((res: Response) => {
        console.log(res);
      })

When I print the response I get in console: enter image description here

I want to have access in the code to body field in the response. The 'body' field starts with an underscore, which means that it's a private field. When I change it to 'console.log(res._body)' I got an error.

Do you know any getter function that can help me here?

Excipient answered 13/4, 2017 at 13:52 Comment(1)
See here, https://mcmap.net/q/340550/-property-39-error-39-does-not-exist-on-type-39-quot-quot-promise-lt-any-gt-39, then you can use res.json().results to get the returned array.Lucrative
W
65

Both Request and Response extend Body. To get the contents, use the text() method.

this.http.request('http://thecatapi.com/api/images/get?format=html&results_per_page=10')
    .subscribe(response => console.log(response.text()))

That API was deprecated in Angular 5. The new HttpResponse<T> class instead has a .body() method. With a {responseType: 'text'} that should return a String.

Walloper answered 13/4, 2017 at 14:14 Comment(4)
respone.text() , the compiler itself complains that text() doesnt exist for the object.Lungi
@Lungi perhaps you are not using Angular 2?Walloper
@OrangeDog, Yes am using Angular7Lungi
.body() didn't work for me but .text() did. Made a note that it might need to be changed in the future.Sturgeon
J
20

Here is an example to access response body using angular2 built in Response

import { Injectable } from '@angular/core';
import {Http,Response} from '@angular/http';

@Injectable()
export class SampleService {
  constructor(private http:Http) { }

  getData(){

    this.http.get(url)
   .map((res:Response) => (
       res.json() //Convert response to JSON
       //OR
       res.text() //Convert response to a string
   ))
   .subscribe(data => {console.log(data)})

  }
}
Jez answered 5/8, 2017 at 5:39 Comment(0)
P
11

Here is an example of a get http call:

this.http
  .get('http://thecatapi.com/api/images/get?format=html&results_per_page=10')
  .map(this.extractData)
  .catch(this.handleError);

private extractData(res: Response) {
   let body = res.text();  // If response is a JSON use json()
   if (body) {
       return body.data || body;
    } else {
       return {};
    }
}

private handleError(error: any) {
   // In a real world app, we might use a remote logging infrastructure
   // We'd also dig deeper into the error to get a better message
   let errMsg = (error.message) ? error.message :
   error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        console.error(errMsg); // log to console instead
        return Observable.throw(errMsg);
}

Note .get() instead of .request().

I wanted to also provide you extra extractData and handleError methods in case you need them and you don't have them.

Patmore answered 13/4, 2017 at 13:57 Comment(1)
I have updated my answer to use text() instead of json().Patmore
T
5

The response data are in JSON string form. The app must parse that string into JavaScript objects by calling response.json().

  this.http.request('http://thecatapi.com/api/images/get?format=html&results_per_page=10').
  .map(res => res.json())
  .subscribe(data => {
    console.log(data);
  })

https://angular.io/docs/ts/latest/guide/server-communication.html#!#extract-data

Tetrarch answered 13/4, 2017 at 14:8 Comment(2)
I get an error: Property 'map' does not exist on type 'Observable<Response>'Excipient
Try to import 'rxjs/add/operator/map'Tetrarch
S
5

I had the same issue too and this worked for me try:

this.http.request('http://thecatapi.com/api/images/get?format=html&results_per_page=10').
  subscribe((res) => {
    let resSTR = JSON.stringify(res);
    let resJSON = JSON.parse(resStr);
    console.log(resJSON._body);
  })
Somniferous answered 22/3, 2018 at 12:55 Comment(0)
D
4

Can't you just refer to the _body object directly? Apparently it doesn't return any errors if used this way.

this.http.get('https://thecatapi.com/api/images/get?format=html&results_per_page=10')
            .map(res => res)
            .subscribe(res => {
                this.data = res._body;
            });

Working plunker

Dehydrogenate answered 13/4, 2017 at 13:54 Comment(2)
Yes this is typically how I do it. I have even seen this way done in Pluralsight courses. My choice for the right answer.Basswood
Why would you use a map function which returns its argument? Wouldn't it accomplish exactly nothing?Rounders
P
4

Unfortunately, many of the answers simply indicate how to access the Response’s body as text. By default, the body of the response object is text, not an object as it is passed through a stream.

What you are looking for is the json() function of the Body object property on the Response object. MDN explains it much better than I:

The json() method of the Body mixin takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.

response.json().then(function(data) { console.log(data);});

or using ES6:

response.json().then((data) => { console.log(data) });

Source: https://developer.mozilla.org/en-US/docs/Web/API/Body/json

This function returns a Promise by default, but note that this can be easily converted to an Observable for downstream consumption (stream pun not intended but works great).

Without invoking the json() function, the data, especially when attempting to access the _body property of the Response object, will be returned as text, which is obviously not what you want if you are looking for a deep object (as in an object with properties, or than can’t be simply converted into another objected).

Example of response objects

Plenteous answered 29/9, 2017 at 14:45 Comment(0)
B
4
.subscribe(data => {   
            console.log(data);
            let body:string = JSON.parse(data['_body']);`
Bahrain answered 8/12, 2017 at 13:37 Comment(1)
While this may answer the question, it is better to explain the essential parts of the answer and possibly what was the problem with OPs code.Tera
D
2

You can try using HttpResponse @angular/common/http.

subscribe((res: HttpResponse<any>) => { console.log(res.body) })

Don't forget to import import { HttpResponse } from '@angular/common/http';

Diacaustic answered 5/6, 2021 at 14:46 Comment(2)
Is there an better option to use the any within the HttpResponse<any>?Ataliah
yap the use of HttpResponseBaseAtaliah
G
1

Below one will work in all versions of Angular:

let body = JSON.parse(JSON.stringify(response)).body;
Gokey answered 21/5, 2021 at 9:48 Comment(0)
D
-2

This is work for me 100% :

let data:Observable<any> = this.http.post(url, postData);
  data.subscribe((data) => {

  let d = data.json();
  console.log(d);
  console.log("result = " + d.result);
  console.log("url = " + d.image_url);      
  loader.dismiss();
});
Dewain answered 11/9, 2018 at 8:59 Comment(0)
U
-3

This should work. You can get body using response.json() if its a json response.

   this.http.request('http://thecatapi.com/api/images/get?format=html&results_per_page=10').
      subscribe((res: Response.json()) => {
        console.log(res);
      })
Uncommunicative answered 11/12, 2017 at 5:21 Comment(3)
This will definitely not work. Response is a type, not a value. You can't call methods on it.Rounders
@ManPersonson it won't work, but that's not why. Every thing in JavaScript is a value. Every value has "methods" that can be called. Response is a function, not a type.Walloper
@Walloper Yea, but not in this context. That's a type annotation. And it's deprecated, and he's trying to call an instance method on the class itself. In Typescript classes are types.Rounders

© 2022 - 2024 — McMap. All rights reserved.