Fabio Carvalho
Fabio Carvalho

Reputation: 469

Angular 6 Http client custom url and header

I am working in an Angular 6 application and I was wondering what should be the best practice when customizing the url while sending requests to the server.

Here is the scenario: - In my Angular project I have the environment.ts and environment.prod.ts where I added a "host" which contains the url:port of the http server (project with the controllers). - I am creating Services to be injected in my components which will be responsible for sending requests (GETs and POSTs) to the server to retrieve data or to send updates. - I want to use the "host" from the environment.ts as part of the request url. So ALL my requests will have the "host" as the base url and then i can concatenate to the desired path.

I already checked a few solutions and I already implemented one of them, but I am not sure this is the right practice. I will write below what i implemented so far and then i will write some ideas, please help me understand what is the best solution (I am new at angular)

Currently implemented:

-> In my feature services, like LoginService, I inject the angular HttpClient. Then I simply call:

return this.httpService.post("/login/", creds).pipe(
      map((data: any) => {
        this.manager = data;
        return this.manager;
      }));

I created an interceptor to make changes to the url: InterceptService implements HttpInterceptor where I create a new instance of the HttpRequest and customize the request.url using environment.host. I also needed the interceptor to add a Header for the authentication (still not fully implemented)

const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
    request = Object.assign(request, httpRequest);

    const headers = new HttpHeaders({
      'Authorization': 'Bearer token 123',
      'Content-Type': 'application/json'
    });

Questions:

1) This works, all my requests are changed in the interceptor as I wanted, but it doesn't look like the best practice in my first look. I don't like to create a new HeepRequest to be able to do this (i did it to keep it immutable, I guess that's the correct way). Do you think this looks good?

2) What about the Authentication being added to the Header in the interceptor? Is it ok? Most of the references I checked did this

Other solutions:

1) I saw some examples where a HttpClientService extends Http and each of the methods such as get and post edit the url and headers before calling super methods. But I believe this is not Angular 6 and is probably not preferrable

2) I could also create a service that receives an angular HttpClient (angular 6 HttpClientModule) instance by injection and I could implement the methods like get or post.

Upvotes: 2

Views: 4955

Answers (1)

Fabio Carvalho
Fabio Carvalho

Reputation: 469

Well, as I didn't get any answers I will add my solution. i believe it's the best solution based on my researches.

I used an interceptor for adding information to the header such as the token bearer authentication.

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpResponse,
  HttpHeaders,
  HttpErrorResponse
} from '@angular/common/http'
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { environment } from "../../../environments/environment";
import { Router } from "@angular/router";

export class HttpClientInterceptor implements HttpInterceptor {

  constructor(private router: Router) { }

  // intercept request to add information to the headers such as the token
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    //I decided to remove this logic from the interceptor to add the host url on the HttpClientService I created
    //const httpRequest = new HttpRequest(<any>request.method, environment.host + request.url, request.body);
    //request = Object.assign(request, httpRequest);

    var token = localStorage.getItem("bearerToken");

    if (token) {
      const newReq = request.clone(
        {
          headers: request.headers.set('Authorization',
            'Bearer ' + token)
        });

      return next.handle(newReq).pipe(
        tap(event => {
          if (event instanceof HttpResponse) {
            console.log("Interceptor - HttpResponse = " + event.status); // http response status code
          }
        }, error => {
          // http response status code
          if (error instanceof HttpErrorResponse) {
            console.log("----response----");
            console.error("status code:");
            console.error(error.status);
            console.error(error.message);
            console.log("--- end of response---");

            if (error.status === 401 || error.status === 403) //check if the token expired and redirect to login
              this.router.navigate(['login']);
          }
        })
      )
    }
    else {
      return next.handle(request);
    }
  };

For changing the url, I created a service on file http-client.service.ts and got the host url from environment.ts

import { Injectable } from "@angular/core";
import { HttpClient } from '@angular/common/http';
import { Observable } from "rxjs";
import { environment } from "../../../environments/environment";

@Injectable({ providedIn:'root' })
export class HttpClientService {
  constructor(private http: HttpClient) { }

  get(url: string, options?: any): Observable<ArrayBuffer> {
    url = this.updateUrl(url);
    return this.http.get(url, options);
  }

  post(url: string, body: string, options?: any): Observable<ArrayBuffer> {
    url = this.updateUrl(url);
    return this.http.post(url, body, options);
  }

  put(url: string, body: string, options?: any): Observable<ArrayBuffer> {
    url = this.updateUrl(url);
    return this.http.put(url, body, options);
  }

  delete(url: string, options?: any): Observable<ArrayBuffer> {
    url = this.updateUrl(url);
    return this.http.delete(url,options);
  }

  private updateUrl(req: string) {
    return environment.host + req;
  }
}

As i said, I believe this is the best approach, but feel free to add information to my question/answer.

Upvotes: 3

Related Questions