DEV Community

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

Posted on

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

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 😁😁🤘🤘🤘

Top comments (9)

Collapse
 
guilhermemgbr profile image
GuilhermeMGBR

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!

Collapse
 
renancferro profile image
Renan Ferro

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

Collapse
 
jangelodev profile image
João Angelo

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

Collapse
 
renancferro profile image
Renan Ferro

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

Collapse
 
wellington1993 profile image
Wellington Torrejais da Silva

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

Collapse
 
renancferro profile image
Renan Ferro

Eaee man

Bem legal né?! Facilita bastante 😆

Collapse
 
prog_25 profile image
prog-24

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

Collapse
 
renancferro profile image
Renan Ferro

Yes, things get more interesting each time 🤣

Collapse
 
makdeniss profile image
Deniss M

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.

Some comments have been hidden by the post's author - find out more