Interceptor - Angular
Considere um projeto onde o usuário efetua o login, recebe um JWT como resultado da autenticação e então o usuário pode consultar ou editar suas informações de perfil passando o JWT para se identificar. Os principais arquivos do projeto seriam mais ou menos o seguinte:
projeto/
├── components/
│ ├── login.component.ts
│ └── profile.component.ts
├── services/
│ ├── login.service.js
│ └── profile.service.ts
Repare bem que após o usuário efetuar o login, ele recebe um JWT que podemos guardar na sessionStorage
por exemplo.
Para obter as informações do perfil do usuário logado ou editá-las, é necessário informar na requisição o JWT para que a API saiba quem é o usuário. Então o arquivo profile.service.ts
teria a seguinte cara:
Repare que informamos o header Authorization
nas duas requisições.
Até este momento estamos falando de uma única service, ProfileService
, mas imagine que este sistema irá crescer e teremos diversas outras services. Vamos ter que adicionar em todas as requisições o header Authorization
, mas a forma como foi demonstrado acima não é a melhor saída. O ideal é que alguém possa interceptar todas as requisições e adicionar este header Authorization
de forma automática. Este alguém é o HttpInterceptor
.
Sempre que for necessário interceptar as requisições partindo da sua aplicação, o interceptor é o recurso que te ajudará.
HttpInterceptor
Para construir o seu próprio interceptor é necessário herdar a interface HttpInterceptor
que está em @angular/common/http
. A interface tem o seguinte formato:
interface HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>>
}
Logando as requisições com HttpInterceptor
Como primeiro exemplo vou mostrar como implementar e utilizar um interceptor com o objetivo de "printar" no console algumas informações sobre as requisições que sua aplicação Angular está fazendo:
A implementação da classe é bem simples, basta implementar a interface HttpInterceptor
e "rechear" o método intercept
.
Falando um pouco deste método, intercept
, ele recebe dois parâmetros:
req: HttpRequest<any>
: objeto com as informações da requisição que foi efetuada na sua aplicação.next: HttpHandler
: representa o próximo interceptor da sua cadeia, ou seja, sua aplicação pode ter vários interceptors, então onext
indica que ou passamos para o próximo interceptor ou a requisição já pode ser efetuada para o backend.
Bom, já com a classe implementada, precisamos "dizer" ao Angular que é para usar este Interceptor. Para isto, podemos indicar através de um provider
no AppModule
:
Observação: a service utilizada neste exemplo não tem conteúdo relevante. Ela possui 2 métodos que efeturam requisições distintas. De qualquer forma no final do artigo deixei um link com o projeto completo.
Resultado:
Veja no GIF acima que ao clicar nos botões Ativar teste 1
e Ativar teste 2
, é efetuada uma requisição HTTP e nosso interceptor entra em ação efetuando os prints no console. Na service que faz a requisição não existe nenhuma referencia a estes console.log
ou ao nosso interceptor:
Repare bem que não importa a quantidade de services que você terá em seu projeto, todas as requisições serão interceptadas pelo LogInterceptor
no caso do nosso exemplo.
Modificando as requisições com HttpInterceptor
Agora que vimos como construir e utilizar um HttpInterceptor
, vamos avançar um pouco mais e modificar todas as requisições com o objetivo de adicionar o cabeçalho (header) Authorization
com o JWT comentado no início deste artigo.
Então vamos criar um outro interceptor chamado AuthorizationInterceptor
:
Como dito anteriormente, vamos registrar este novo interceptor no AppModule
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { LogInterceptor } from './interceptor/log.interceptor';
import { AuthorizationInterceptor } from './interceptor/authorization.interceptor';
@NgModule({
imports: [ BrowserModule, FormsModule, HttpClientModule ],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass:
LogInterceptor,
multi: true
}, {
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationInterceptor,
multi: true
}]
})
export class AppModule { }
Observe que a partir de agora temos 2 interceptors e o header Authorization
passa a existir em todas as requisições efetuadas pela aplicação.
As setas na imagem abaixo indicam os prints que os 2 interceptores efetuam e o quadrado vermelho a direita indica a presença do novo header Authorization
:
Pensando em nosso cenário inicial, onde precisaríamos passar o header Authorization
em todas as requisições, a melhor forma de fazer isto é com um interceptor conforme o exemplo acima.
Considerações
Perceba que o interceptor pode ajudar em vários casos, podemos fazer um log das requisições, modificar cabeçalhos, modificar o próprio corpo da requisição, tratar erros de uma forma mais genérica, etc. Deixo como sugestão a leitura deste link.
Exemplo completo:
Links: