Implementação de Interceptor para requisições HTTP em aplicação Angular 10

Irei apresentar nesse post um assunto que me custou tempo no início para entender os Interceptors do Angular.

O que é ?

Interceptor, permite interceptar e tratar as requisições antes de serem disparadas para o servidor/api.

Isso possibilita fazer varias coisas, um exemplo seria configurar uma autenticação via token em qualquer requisição, ou de repente adicionar headers personalizados que a aplicação possa necessitar, e até tratar respostas antes de terminar a requisição. Apresenta diversas possibilidades de implementação.

Com Angular 4+ essa tarefa fica encarregado graças a classe HttpClient.

Bora para a prática...

Crie uma aplicação base do Angula. Atualmente está na versão 10. Sabendo que já esteja com o Node instalado na sua máquina.

Instale o Angular CLI globamente na máquina:

npm install -g @angular/cli
ng new my-interceptor
cd my-interceptor

Com isso será criado um projeto padrão do Angular chamado MyInterceptor, ou de sua preferencia de ser chamado.

Abra a pasta do projeto e segue a o caminho src>app, feito isso, crie uma nova pasta chamada auth e dentro dela crie um modulo, que será para facilitar na importação do modulo principal e um interceptor, como demostro abaixo usando o comando ng generate:

Para a criação do modulo interceptor dentro da pasta auth:

ng generate module auth/interceptor

ou

ng g m auth/interceptor

Será criado esse modulo:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';



@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})
export class InterceptorModule { }

Para a criação do interceptor dentro da pasta auth:

ng generate interceptor auth/http-request

ou

ng g i auth/http-request

Será criado esse interceptor, junto com o spec(mas não é necessário, é para caso de testes):

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

@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request);
  }
}

*Caso no momento de gerar o modulo e o interceptor, eles ficarem em pastas separadas é só mover. Mas gosto de deixar tudo na mesma pasta. Só en ocasião de um projeto grande colocar em pasta separadas. Nesse caso coloquei o modulo e o interceptor na mesma pasta auth.

Configurando o módulo interceptor:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

import { HttpRequestInterceptor } from './http-request.interceptor';


@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ],
  providers: [
    {
     provide: HTTP_INTERCEPTORS,
     useClass: HttpRequestInterceptor,
     multi: true,
    },
   ],
})
export class InterceptorModule { }

Configurando o interceptor:

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

@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    const duplicRequest = request.clone({
      headers: request.headers.set('key', '123456789'),
    });
    return next.handle(duplicRequest);
  }
}

Explicando o código:

Ele inicia importando tudo que é necessário para a implementação do Inteceptor. Os recursos HttpEvent, HttpInterceptor, HttpHandler e HttpRequest fazem parte do HttpClient do Angular. Facilitando a vida do desenvolvedor.

Em seguida, foi criado uma classe chamada HttpsRequestInterceptor que implementa a interface HttpInterceptor.

Para que consiga interceptar a requisição e eventualmente adicionar mais informações, é necessário duplicá-la antes de mandar para o servidor. Fazendo isso com o intercept e dentro configuramos qual tipo de requisição queremos afetar ( request: HttpRequest<any>) e o controlador que nos permite passar o objeto modificado adiante (next: HttpHandler).

Retorno do objeto modificado na última linha do intercept

return next.handle(duplicRequest);

Para finalizar, basta importar no módulo principal da aplicação app.module.ts o modulo do Interceptor.

Portanto, qualquer requisição dentro de sua aplicação, irá mandar um header key com valor123456789 configurado no *interceptor.module.ts.*

Chamando uma requisição API e conferindo o header customizado:

Será consumido uma api qaulquer em nosso componentes apenas para demonstração. Dentro de *app.component.ts(pode fazer em qualquer component). Como demostração vamos fazer assim que o component for criado no* ngOnInit(), sempre que solicitamos uma requisição a uma API, seja ela GET, POST, colocamos uma pasta services. Então cria um service com o ng generate, nesse caso criei um service chamado de api na pasta services:

Para a criação do interceptor dentro da pasta auth:

ng generate service services/api

ou

ng g i services/api

Será criado esse service, junto com o spec(mas não é necessário, é para caso de testes):

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';

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

  find() {
    return this.http.get('https://jsonplaceholder.typicode.com/posts');
  }
}

No exemplo acima fazemos uma requisição post para essa API, mas fica a seu criterio fazer a requisição em qualquer API.

No app.component.ts será chamado esse service dentro do construtor.

constructor(private api: ApiService) {}

import a ApiService no app.component.ts e certifique se ele está no importado no providers do app.module.ts

.
.
.
  providers: [
    ApService
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Finalizando, dentro do método ngOnInit() faça a chamada para a ApiService:

data: any;

constructor( private api: ApiService) {}

ngOnInit(): void {
    this.api.find().subscribe((resp) => {
      this.data = resp;
    });

Finalmente verificar se o header foi configurado, basta rodar a aplicação com ng serve ou npm run start no terminal e abrir o devtools do seu browser.

Na aba network, clique em cima da requisição que você fez e verifique os headers na seção request headers, como na imagem abaixo:

headers customizado

Na imagem acima, o header customizado é passado na requisição. Claro que foi um exemplo meramente ilustrativo nesse caso, mas poderiamos facilmente validar essa key no backend para autenticações de login, sessão, para tudo que imaginar, enfim fica na sua imaginação.

Espero que tenha passado um pouco do conhecimento. Qualquer dúvida, correção ou sugestão eu estarei a disposição.

Comentários