Angular 12 http request : invalid URL

Viewed 578

I'd like make a request on : https://jsonplaceholder.typicode.com/users but I get an Invalid URL error but the URL is ok to me. I really don't understand why.

Error message : Message: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL

export class User {
    id: string;
    name: string;
    email: string;
    username: number;
}

import { User } from '../models/user';

@Injectable({
  providedIn: 'root'
})

export class UserService {

  // REST API
  endpoint = 'https://jsonplaceholder.typicode.com/';

  constructor(private httpClient: HttpClient) { }

  getUsers(): Observable<User> {
    return this.httpClient.get<User>(this.endpoint + 'users')
    .pipe(
      retry(1),
      catchError(this.processError)
    )
  }

  processError(err) {
    let message = '';
    if(err.error instanceof ErrorEvent) {
     message = err.error.message;
    } else {
     message = `Error Code: ${err.status}\nMessage: ${err.message}`;
    }
    console.log(message);
    return throwError(message);
 }
}

In the component :

export class UserListComponent implements OnInit {

  Users: any = [];

  constructor(private crudService: UserService) {}
  ngOnInit() {
    this.fetchUsers();
  }

  fetchUsers() {
    return this.crudService.getUsers().subscribe((res: {}) => {
      this.Users = res;
    })
  }

}

In the html

    <table class="table">
      <thead>
        <tr class="table-primary">
          <th>#User Id</th>
          <th>Name</th>
          <th>Us
er Name</th>
          <th>Email</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of Users">
          <th scope="row">{{data.id}}</th>
          <td>{{data.name}}</td>
          <td>{{data.username}}</td>
          <td>{{data.email}}</td>
        </tr>
      </tbody>
    </table>
1 Answers

Here is a working stackblitz: Seems to have to do with your typings maybe, I'm not too sure. But this code does work, and it uses the correct typing and observes the entire HttpResponse instead of just the body of it. This also implements User as an interface and not a class. This is recommended unless you need more functionality than just type enforcement of attributes. Also notice that to get the Json data in the subscription, it is in res.body. This also correctly implements OnDestroy to unsubscribe to the subscription, which is always good practice if you aren't using an async pipe.

https://stackblitz.com/edit/angular-ivy-ue5zf4

Component File:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { UserService } from './user-service';
import { User } from './user-interface'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})

export class AppComponent implements OnInit, OnDestroy {
  private unsubscribe$ = new Subject<void>();
  users: User[] = [];

  constructor(private userService: UserService){}

  ngOnInit(): void {
    this.userService.getUsers().pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {
      this.users = res.body;
    });
  }

  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}

Service:

import { Injectable } from "@angular/core";
import {
  HttpClient,
  HttpResponse,
} from "@angular/common/http";
import { Observable, of, throwError } from "rxjs";
import { catchError, retry, tap } from "rxjs/operators";
// Interface for user
import { User } from './user-interface';

@Injectable({
  providedIn: 'root'
})

export class UserService {

  // REST API
  endpoint = 'https://jsonplaceholder.typicode.com/';
  usersApi = "users";

  constructor(private http: HttpClient) { }

  getUsers(): Observable<HttpResponse<User[]>> {
    return this.http.get<User[]>(this.endpoint + this.usersApi, { observe: "response"})
    .pipe(
      retry(1),
      catchError(this.processError)
    )
  }

  processError(err) {
    let message = '';
    if(err.error instanceof ErrorEvent) {
     message = err.error.message;
    } else {
     message = `Error Code: ${err.status}\nMessage: ${err.message}`;
    }
    console.log(message);
    return throwError(message);
 }
}

User Interface:

export interface User {
  id: string;
  name: string;
  email: string;
  username: number;
}

App Module:

import { NgModule } from '@angular/core';
import { CommonModule } from "@angular/common";
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from "@angular/common/http";
import { AppComponent } from './app.component';
    
@NgModule({
  imports:      [ BrowserModule, CommonModule, FormsModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

HTML:

<table class="table">
  <thead>
    <tr class="table-primary">
      <th>#User Id</th>
      <th>Name</th>
      <th>User Name</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let data of users">
      <th scope="row">{{data.id}}</th>
      <td>{{data.name}}</td>
      <td>{{data.username}}</td>
      <td>{{data.email}}</td>
    </tr>
  </tbody>
</table>

User Result

Related