2

My backend API http://localhost:8300/api/picture returns a string and I have tried following approaches: ( getpicture is called on button click)

Approach 1:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-auth-success',
  templateUrl: './auth-success.component.html',
  styleUrls: ['./auth-success.component.scss']
})
export class AuthSuccessComponent implements OnInit {

  showImg: boolean = false;
  imgUrl: string = "";

  constructor(private http: HttpClient) { }

  ngOnInit() {    

  }
    getPicture(){
        this.http.get("http://localhost:8300/api/picture",{ observe: 'response' })                                                   
                .subscribe(
                  res => { 
                    console.log(res);                   
                    this.onSuccess(res);
                  }, error => {
                          console.error("Some error while calling backed");
                        });
      }

      onSuccess(data: any){
        this.imgUrl = data;
        this.showImg = true;
      }
}

And HTML:

<div>
 <button (click)="getPicture()">Google Picture</button><br><hr><hr>

 <img [src]="imgUrl" *ngIf="showImg">
 </div>

Output:

"Some error while calling backed" found (i.e. error is printed)

Approach 2:

 getPicture(){
        this.http.get("http://localhost:8300/api/picture")
                .map((res : Response)=> {
                  console.log(res); // correct value printed if below line is commented
                  this.imgUrl = res.text(); // compiler gives error at this line
                })                                                   
                .subscribe();

      }

Output: I get compiler error:

Type Promise<string> is not assignable to type 'string'.

What am I missing?

EDIT: I have removed the custom error message that was getting printed

"Image not found"

with console.error(error) as it was creating a confusion that my backend is returning this error. The error message printed is:

e {headers: t, status: 200, statusText: "OK", url: "http://localhost:8300/api/picture", ok: false, …} error : {error: SyntaxError: Unexpected token h in JSON at position 0 at JSON.parse () at XMLHttp…, text: "https://lh3.googleusercontent.com/-46Nb-WbneSU/AAAAAAAAAAI/AAAAAAAAAAc/V7Pz0b9mxdw/photo.jpg"} headers : t {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ} message : "Http failure during parsing for http://localhost:8300/api/picture" name : "HttpErrorResponse" ok : false status : 200 statusText : "OK" url : "http://localhost:8300/api/picture"

tryingToLearn
  • 10,691
  • 12
  • 80
  • 114
  • Can you paste a sample response from API here? – sabithpocker Feb 23 '18 at 08:23
  • 1
    @theLearner, "map" it's used to transform the response, not to make a call function (you can use "do"). You get the response in "subscribe", so your first aproach is the correct. Sure you use HttpClient, try to write console.log(error) to see the error – Eliseo Feb 23 '18 at 08:37
  • @Eliseo any idea about the error message: `Type Promise is not assignable to type 'string'.` – tryingToLearn Feb 23 '18 at 09:08

1 Answers1

2

As explained in this answer, Http was inspired by Fetch API and has classes of same names, though they aren't compatible, because Http uses observables, and Fetch API uses promises.

The implication is that if Response wasn't imported, global Response will be used. Since Response is used here only as a type, the problem affects types only. There should be:

import { Response } from '@angular/http';

This doesn't apply to HttpClient. The main difference in the code that uses HttpClient is that response negotiation is performed with observe and responseType options, and .map((res) => res.text()) line should be omitted.

Approach 1 uses observe: 'response' which isn't needed here, but doesn't set responseType which defaults to json and results in JSON parse error. Approach 2 uses Http API, while http is HttpClient.

map isn't a proper place for side effects. Dummy subscribe() indicates that an observable is misused here. If there's no benefit from using observables, a promise may be more convenient option:

async getPicture(){
  try {
    this.imgUrl = await this.httpClient.get("http://localhost:8300/api/picture", { responseType: 'text' })
    .toPromise();

    this.showImg = true;
  } catch (e) {
    ...
  }
}

This isn't relevant to original problem, Image not found. Backend API responds with an error. This has nothing to do with Angular and should be fixed, depending on the backend.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • I have put a breakpoint at backend and backend is returning the correct string always i.e. in both the approaches. Also as I mentioned in my question that if I use **Approach 2**, and print the response, the response returned by backend is printed correctly(the error comes when I try to assign it to my local variable). `Image not found` is printed in **Approach 1** and angular is printing it because in `console.error` I have given that message. – tryingToLearn Feb 23 '18 at 09:00
  • I have changed the error message as it was creating confusion. – tryingToLearn Feb 23 '18 at 09:07
  • It doesn't really matter what backend debugging says. It matters what the browser receives. You can check this in dev tools network tab. There can be countless reasons why there may be an error, and you're the only person who can output `error` and check what's wrong. Approach 1 won't work correctly because there's no res.text(), but it won't cause this error. Any way, the question covers what's wrong with Angular code. The rest depends on your backend. Hope this helps. – Estus Flask Feb 23 '18 at 09:09
  • Notice that the answer assumes that you use Http. This is what the code in the question implies. This won't be true for HttpClient – Estus Flask Feb 23 '18 at 09:20
  • This is a very silly mistake on my part. I am using `HttpClient`. I should have posted the complete file. Edited the question now. – tryingToLearn Feb 23 '18 at 09:25