1

I can't understand why my endpoint in the backend is addressed twice. This is my code:

HttpService

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { ApiMethod, AuthEndPoints } from '../conts';
import { environment } from '../../../../environments/environment';
import { catchError } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class HttpService {

  constructor(private http: HttpClient) {
  }

  /**
   * This function is used to make api calls.
   * It takes an apiMethod name, the api url and for
   * post and put it takes also the data which should be
   * send
   *
   * @param api AuthEndPoints
   * @param method ApiMethod
   * @param data any
   */
  requestCall(method: ApiMethod, api: AuthEndPoints, data?: any): Observable<any> {
    console.log("HttpService")
    let response;
    switch (method) {
      case ApiMethod.GET:
        response = this.http.get(`${environment.baseUrl}${api}`).pipe(
          catchError(err => this.handleError(err, this))
        );
        break;
      case ApiMethod.POST:
        response = this.http.post(`${environment.baseUrl}${api}`, data).pipe(
          catchError(err => this.handleError(err, this))
        );
        break;
      case ApiMethod.PUT:
        response = this.http.put(`${environment.baseUrl}${api}`, data).pipe(
          catchError(err => this.handleError(err, this))
        );
        break;
      case ApiMethod.DELETE:
        response = this.http.delete(`${environment.baseUrl}${api}`).pipe(
          catchError(err => this.handleError(err, this))
        );
        break;
    }
    return response;
  }

  /**
   * This function is used to handle the error
   * which can occure from an api call
   *
   * @param error HttpErrorResponse
   */
  handleError(error: HttpErrorResponse, self): any {
    // if (error.error instanceof ErrorEvent) {
    //   console.error('An error occured:', error.error.message);
    // } else {
    //   this._error.whichError(error.status, error.message);
    //   return throwError({error: error.message, status: error.status});
    //}
  }

}

This function is called in the authService:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpService } from '../../core/services/http/http.service';
import { ApiMethod, AuthEndPoints } from '../../core/services/conts';
import { StorageService } from '../../core/services/storage/storage.service';

export interface LoginForm {
  email: string;
  password: string;
}

export interface User {
  name?: string;
  username?: string;
  email?: string;
  password?: string;
  passwordConfirm?: string;
}


@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(
    private http: HttpService,
    private router: Router,
    private storage: StorageService
  ) { }
   

  login(loginForm: LoginForm) {
    console.log("Login - AuthService")
    this.subscription =  this.http.requestCall(ApiMethod.POST, 
   AuthEndPoints.LOGIN, loginForm).subscribe(res => {
      console.log("Login - Observable")
      this.storage.saveToken(JSON.stringify(res.auth_token));
      this.router.navigate(['/dashboard']);
    }, (error) => {console.log(error)})
  }

And the login function from the authService is called in the loginComponent:

import { Component, OnInit} from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../../service/auth.service';
import { Router } from '@angular/router';

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

export class LoginComponent implements OnInit {

  loginForm: FormGroup;
  submitted = false; // implementieren

  constructor(
    private authService: AuthService) {
  }

  ngOnInit(): void {
    this.initLoginForm();
  }

  /**
   * loginForm
   */
  initLoginForm(): void {
    this.loginForm = new FormGroup({
      email: new FormControl(null, [
        Validators.required,
        Validators.email,
        Validators.minLength(8)
      ]),
      password: new FormControl(null, [
        Validators.required,
        Validators.minLength(4)
      ])
    });
  }

  /**
   * onSubmit
   */
  onSubmit() {
    if (this.loginForm.invalid) {
      return;
    }
console.log("LoginComponent")
    this.authService.login(this.loginForm.value)
  }
}

LogingComponentHtml:

<mat-toolbar color="primary">
  <mat-toolbar-row>
    <h1 style="text-align: center !important; width: 100%">Login Page</h1>
  </mat-toolbar-row>
</mat-toolbar>
<div class="row">
  <div class="col-md-12">
    <form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
      <div class="container">

        <div class="form-group">
          <mat-form-field>
            <label>
              <input formControlName="email" matInput placeholder="E-Mail">
            </label>
          </mat-form-field>
        </div>

        <div class="form-group">
          <mat-form-field>
            <label>
              <input formControlName="password" matInput placeholder="Password">
            </label>
          </mat-form-field>
        </div>

        <button mat-flat-button color="primary" [disabled]="!loginForm.valid" type="submit">Login</button>
      </div>
    </form>
  </div>
</div>

I log the endpoints in the BackEnd. Therefore I can see that the endpoint is addressed 2 times.

enter image description here

But when I access the endpoint via Postman, the endpoint is only accessed once.

enter image description here

Client-Side log: enter image description here

Network-Tab: enter image description here

I thought maby it is because I have not unsubscribed the observable. So i tried the follwoing:

constructor(
    private http: HttpService,
    private router: Router,
    private storage: StorageService
  ) { }

   subscription: Subscription



  login(loginForm: LoginForm) {
    this.subscription =  this.http.requestCall(ApiMethod.POST, AuthEndPoints.LOGIN, loginForm).subscribe(res => {
      this.storage.saveToken(JSON.stringify(res.auth_token));
      this.router.navigate(['/dashboard']);
    }, (error) => {console.log(error)})
  }


  ngOnDestroy() {
    this.subscription.unsubscribe()
  }

But that does not change.

Do you have any ideas? Am I doing something fundamentally wrong here? Or has anyone ever had this problem?

Hubi
  • 440
  • 1
  • 11
  • 25
  • 1
    I recommend adding logs on a client-side as well: 1. At the beginning of the **login** method (to ensure that it's called just once). 2. Inside the **subscribe** block (to understand, how many times it gets triggered). Share this info with us, please. – P.S. May 26 '21 at 13:01
  • 1
    Please include `handleError` in your post. Nothing in the code shown should lead to repeated api calls. Also, you can use Networking Tools in the browser to see how may api calls were made – Andrew Allen May 26 '21 at 13:08
  • @AndrewAllen added the handle error function, but it is commented out. So not in Use at this point – Hubi May 26 '21 at 13:17
  • 1
    Looks strange. Is anything interesting in the "network" tab? There is just one call, right? Would be great to take a look at that. – P.S. May 26 '21 at 13:27
  • Yeah, strange. updated the question – Hubi May 26 '21 at 13:55
  • 1
    Oh, that's a preflight request, read about it here https://stackoverflow.com/questions/40497399/http-request-from-angular-sent-as-options-instead-of-post – Andrew Allen May 26 '21 at 14:06

1 Answers1

0

my 2 cents - you should never call subscribe in your service - use map instead

tercou1
  • 113
  • 2
  • 11