Let's understand and make our API requests professional with HTTPInterceptor like a Pro
Renan Ferro

Renan Ferro @renancferro

About: Frontend Developer ❤️‍🔥 | Just learning, practicing, coding and letting a little bit of it spread out forever and ever ➿ Be brave enough to be bad at something new!

Location:
Brazil
Joined:
Apr 20, 2021

Let's understand and make our API requests professional with HTTPInterceptor like a Pro

Publish Date: Jan 8 '24
31 10

Hey guys, how are you today?!

It's 2024, let's make this year wonderful and do a lot of some cool things!

Today I'd like to share and talk about a something interesting and it can do your application and development time better!

So let's see and learning something cool!

👾 The problem

When we have an application consuming an API we basically have this structure:

In this example we have a Github News Application consuming an API

import {environment} from "../../environments/environment";

....

export class GithubNewsService {

  constructor(
    private _httpClient: HttpClient
  ) { }

  getGithubNews(): Observable<GithubNews[]> {
    return this._httpClient
      .get<GithubNews[]>(`${environment.apiGithubNews}/getNews`);
  }

  saveNewGithubNews(news: GithubNews): Observable<GithubNews[]> {
    return this._httpClient
      .post<GithubNews>(`${environment.apiGithubNews}/saveNews`, news);
  }
}
Enter fullscreen mode Exit fullscreen mode

If you nice, we have a bit of duplication in our code. In the getGithubNews and saveNewGithubNews methods we need to pass the APIU url, which we pass using the environment.apiGithubNews.

But let's imagine this application becomes increasingly large with countless services consuming the same API url. And this way that we are using it in the future could cause us some problems, because imagine that one day it becomes necessary to change the variable that was previously apiGithubNews and now has another name, perhaps something like apiGenericNews we would need changing the name in all files generates work and we could possibly break the application, if we lave somewhere without changing!

And I can say, we can resolve this like a pro and with only a file! Let's see this!


👩‍🎨 The solution

Angular offer for us a lot of really and powerfull things, and one of these is the HTTPInterceptor.

🧩 HTTPInterceptor

In a nutshell, with Interceptors we can transform a flow of events by transforming the request before passing it on, calling next.handle() and applying the logic we want!

So, thinking about our "problem" we can put the API url of the request in our HTTPInterceptor, with this we can remove the environment.apiGithubNews from our GithubNewsService and we'll only have one place to change the environment.apiGithubNews, if this ever happens in the future this will change!

This makes our code a little cleaner and easier to apply future changes.

Now, let's work!

🧩 Structuring the Solution

Let's see and apply the structure for the solution.

➾ Generate the HTTPInterceptor file:

First, let's generate the HTTPInterceptor, with Angular CLI we just need put the generate command to generate the file, like below:

ng generate interceptor interceptors/set-domain
Enter fullscreen mode Exit fullscreen mode

➾ Importing the HTTPInterceptor file:

Let's import the our HTTPInterceptor in our app.module.ts inside the providers, so basically the structure will be:

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { SetDomainInterceptor } from './interceptors/set-domain.interceptor';
...

@NgModule({
  ....
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: SetDomainInterceptor,
      multi: true,
    },
  ],
  ...
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

➾ Structuring the SetDomainInterceptor:

As we saw above, we need to take the request flow, apply the logic we want and return the update request with next.handle(), so basically the structure will be like below:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';

@Injectable()
export class SetDomainInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(httpRequest: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {

    const requestStructureUpdated: HttpRequest<any> = httpRequest
        .clone({
          url: `${ environment.urlApi }/${ httpRequest.url }`,
          setHeaders: {
            'Content-Type': 'application/json'
          }
        });

    return next.handle(requestStructureUpdated);
  }
}

Enter fullscreen mode Exit fullscreen mode

Basically, we take the request and create a clone of it, passing the API url with environment.apiGithubNews, after that we concatenate the rest of the request URL with ${ httpRequest.url } and we also apply the 'Content-Type': 'application /json'.

Now in our service structure, we can remove the environment.apiGithubNews and have just the API url path, so the new structure will look like this:

...

export class GithubNewsService {

  constructor(
    private _httpClient: HttpClient
  ) { }

  getGithubNews(): Observable<GithubNews[]> {
    return this._httpClient
      .get<GithubNews[]>('getNews');
  }

  saveNewGithubNews(news: GithubNews): Observable<GithubNews[]> {
    return this._httpClient
      .post<GithubNews>('saveNews', news);
  }
}
Enter fullscreen mode Exit fullscreen mode

Really cool and interesting, right?!

Now with this we can apply and passa whatever we want in all requests in our application, having only one place to do this and keeping our code easy to apply future changes.


We have many possibilities and I hope that with this new possibility you learn something and help you!

I hope you enjoyed today's article!

If know of any other way, have any comments or anything else, please leave a comment and let's talk!

See you soon 😁😁🤘🤘🤘

Comments 10 total

  • prog-24
    prog-24Jan 10, 2024

    Haha, interceptors are really great, once you wrap your head around them, you can begin to appreciate the design pattern.

    • Renan Ferro
      Renan FerroJan 10, 2024

      Yes, things get more interesting each time 🤣

  • Wellington Torrejais da Silva
    Wellington Torrejais da SilvaJan 10, 2024

    Nice idea of use the base URL constant inside the Interceptor!

    • Renan Ferro
      Renan FerroJan 10, 2024

      Eaee man

      Bem legal né?! Facilita bastante 😆

  • João Angelo
    João AngeloJan 10, 2024

    Renan Ferro,
    Great article !
    Thanks for sharing...

    • Renan Ferro
      Renan FerroJan 11, 2024

      Muito obrigado João, fico feliz que tenha gostado 😄

  • Deniss M
    Deniss MJan 15, 2024

    Still thinking their environment files are good for this. If you need to change the baseUrl -> just change the value (per env). Interceptors I would use for something like tokens or something like that. This we don't need to have in services, but we can inject this type of stuff in the interceptors.

  • GuilhermeMGBR
    GuilhermeMGBRFeb 16, 2024

    An alternative to cloning the request would be using an HttpClientFactory with the API URL as an argument. It was interesting seeing an example with HttpInterceptor though!

    • Renan Ferro
      Renan FerroFeb 19, 2024

      Wow, the way you commented too is very interesting! I'll try to understand better and apply it to have another way! Thanks ✌️

Add comment