[Off Topic] Nano introdução do framework Angular para Devs do back
Tags: angular, frontend, component, service
Published: 2024-05-22 11:52:42

Fugindo um pouco do tema do canal, resolvi escrever esse post destinado aos Devs do backend que estão acompanhando a nossa jornada de descoberta da ferramenta JHipster. Caso você tenha caído aqui de paraquedas, trata-se de uma série de posts que começamos [aqui](https://dev.to/meucodigoagil/agile-sem-as-ferramentas-certas-e-so-mais-uma-forma-desorganizada-de-produzir-software-35ii).

Esse post não tem nem mesmo a pretensão de ensinar você a fazer um mero “Hello World” em Angular. A intenção aqui é apenas introduzir um conjunto pequeno de conceitos básicos do Angular para que os desenvolvedores que não têm a menor desenvoltura com frontend possam acompanhar menos agoniados as análises de código gerado pelo JHipster.

Durante as descrições dos conceitos abaixo, quando eu fizer referência a “nossa aplicação”, estou me referindo a uma aplicação monolítica exemplo que foi gerada com o JHipster 8 durante essa série de posts que citei acima. O post da geração da aplicação em si é este aqui, mas se preferir, o código também está no Github.

Estando tudo isso esclarecido, vamos começar? :)

# Componente

uase tudo é um componente no Angular. Podemos entendê-lo como um código que encapsula HTML, CSS e lógica em Typescript. Não por acaso, tipicamente, um componente no Angular é formado por 3 arquivos: um HTML, um arquivo de estilos (CSS ou SCSS) e um arquivo TS. Tomemos como exemplo o componente `app/home` da nossa aplicação:

No arquivo `home.component.scss`, não tem nada além da definição de classes de estilos que vão estipular todas aquelas coisinhas que a galera de UI se amarra: posicionamento, tamanho, fontes, cores … nada que desperte encantos em um Dev do back, mas se for só pra dar uma olhadinha sem compromisso, também não assusta.

```css
.hipster {
  display: inline-block;
  width: 347px;
  height: 497px;
  background: url('../../content/images/jhipster_family_member_3.svg') 
    no-repeat center top;
  background-size: contain;
}
```
No arquivo `home.component.html`, como você já deve ter imaginado, tem um monte de tags HTML, textos, referências a classes CSS. Nada que nós _backenders_ não tenhamos visto antes, certo?

```html
<div class="row">
  <div class="col-md-3">
    <span class="hipster img-fluid rounded"></span>
  </div>
  <div class="col-md-9">
    <h1 class="display-4">
      <span jhiTranslate="home.title">Bem vindo, Java Hipster!</span> 
      (Minha Aplicacao Monolitica)
    </h1>
    <p class="lead" jhiTranslate="home.subtitle">
      Esta é a página principal
    </p>  
...
```

Com exceção de coisinhas como esse `@if (....)` no trecho a seguir. Mas que, muito provavelmente, você já viu algo parecido em soluções que usavam templates como ASP, JSP etc … é só uma lógica de exibição de um trecho de HTML ou outro que faz referência a uma variável/atributo.

```html
<div>
      @if (account() !== null) {
        <div class="alert alert-success">
          @if (account()) {
            <span id="home-logged-message" jhiTranslate="home.logged.message" [translateValues]="{ username: account()!.login }"
              >Você está logado como &quot;{{ account()!.login }}&quot;.</span
            >
          }
        </div>
      } @else {
        <div class="alert alert-warning">
          <span jhiTranslate="global.messages.info.authenticated.prefix">Se deseja </span>
          <a class="alert-link" (click)="login()" jhiTranslate="global.messages.info.authenticated.link">entrar</a
          ><span jhiTranslate="global.messages.info.authenticated.suffix"
            >, utilize as seguintes contas padrões:<br />- Administrador (usuário=&quot;admin&quot; and senha=&quot;admin&quot;) <br />-
            Usuário (usuário=&quot;user&quot; e senha=&quot;user&quot;).</span
          >
        </div>
        <div class="alert alert-warning">
          <span jhiTranslate="global.messages.info.register.noaccount">Não possui uma conta ainda?</span>&nbsp;
          <a class="alert-link" routerLink="/account/register" jhiTranslate="global.messages.info.register.link">Crie uma nova conta</a>
        </div>
      }
```

E adivinhe onde está essa variável … exatamente! Está na classe Typescript declarada no arquivo `home.component.ts` resumida a seguir:

```typescript
@Component({
  standalone: true,
  selector: 'jhi-home',
  templateUrl: './home.component.html',
  styleUrl: './home.component.scss',
  imports: [SharedModule, RouterModule],
})
export default class HomeComponent implements OnInit, OnDestroy {

  account = signal<Account | null>(null);
  ...

  login(): void {
    this.router.navigate(['/login']);
  }
  ...
}
```

Perceba que a classe possui uma anotação `@Component` onde dois dos atributos que a anotação recebe são exatamente o path relativo dos arquivos HTML e SCSS. Outro atributo que cabe chamarmos atenção é o `selector`. Esse atributo define qual será a tag desse componente `HomeComponent` que o JHipster criou pra nós. Isso significa que poderíamos utilizar este componente dentro de outro componente utilizando a tag `jhi-home` como neste exemplo hipotético:

```html
<div>
  <jhi-home></jhi-home>
</div>
```

Você vai encontrar no mesmo diretório o arquivo `home.component.spec.ts`. Por ora, basta saber que se trata dos testes unitários do componente.

Um último ponto para fecharmos a explicação sobre componentes Angular: um componente não precisa necessariamente ter o arquivo de estilos (CSS ou SCSS). Veja, por exemplo, o componente `app/login` da nossa aplicação:

```typescript
@Component({
  selector: 'jhi-login',
  standalone: true,
  imports: [SharedModule, FormsModule, ReactiveFormsModule, RouterModule],
  templateUrl: './login.component.html',
})
export default class LoginComponent implements OnInit, AfterViewInit {
  @ViewChild('username', { static: false })
  username!: ElementRef;
  ...
```

Além de não ter um arquivo de estilos no diretório `login`, perceba que na anotação `@Component` o atributo `styleUrl` também não é setado. Mas olhando o seu template, o arquivo HTML, é possível notar referências a classes de estilo. Entretanto, essas classes vêm da pacote [Bootstrap](https://getbootstrap.com/) ou de algum dos arquivos da pasta `webapp/content/scss`.

```html
<div class="d-flex justify-content-center">
   <div class="col-lg-6 col-md-8 col-sm-10">
     <h1 jhiTranslate="login.title" data-cy="loginTitle">Autenticação</h1>
     @if (authenticationError()) {
       <div class="alert alert-danger" jhiTranslate="login.messages.error.authentication" data-cy="loginError">
         <strong>Erro de autenticação!</strong> Por favor verifique suas credenciais e tente novamente.
       </div>
     }
     <form class="form" role="form" (ngSubmit)="login()" [formGroup]="loginForm">
  ...
```


# Serviço

Aqui está um conceito que não vai deixar nenhum Dev backend desconfortável. Afinal, um Serviço é tão somente uma classe Typescript que fornece funcionalidades específicas para serem reutilizadas por distintas partes da aplicação. Não tem HTML, não tem CSS … é tão somente: CÓ-DI-GO!

Veja, por exemplo, o serviço `app/core/auth/state-storage.service.ts` que, basicamente, encapsula funcionalidades de ler, escrever e apagar dados na [sessionStorage](https://developer.mozilla.org/pt-BR/docs/Web/API/Window/sessionStorage) do navegador.

```typescript
@Injectable({ providedIn: 'root' })
export class StateStorageService {
  private previousUrlKey = 'previousUrl';
  private authenticationKey = 'jhi-authenticationToken';
  private localeKey = 'locale';

  storeUrl(url: string): void {
    sessionStorage.setItem(this.previousUrlKey, JSON.stringify(url));
  }

  getUrl(): string | null {
    const previousUrl = sessionStorage.getItem(this.previousUrlKey);
    return previousUrl ? (JSON.parse(previousUrl) as string | null) : previousUrl;
  }

  clearUrl(): void {
    sessionStorage.removeItem(this.previousUrlKey);
  }
```

Sabe outro tipo de funcionalidade que também fica a cargo de Serviços? Requisições HTTP a APIs! Veja abaixo um trecho do serviço `app/entities/produto/service/produto.service.ts`:

```typescript
@Injectable({ providedIn: 'root' })
export class ProdutoService { 

  protected http = inject(HttpClient);
  protected applicationConfigService = inject(ApplicationConfigService);

  protected resourceUrl = this.applicationConfigService.getEndpointFor('api/produtos');

  create(produto: NewProduto): Observable<EntityResponseType> {
    return this.http.post<IProduto>(this.resourceUrl, produto, { observe: 'response' });
  }

  ...
  find(id: number): Observable<EntityResponseType> {
    return this.http.get<IProduto>(`${this.resourceUrl}/${id}`, { observe: 'response' });
  }

  ...
```

Apenas para ficar mais claro, selecionei um método do componente `app/entities/produto/update/produto-update.component.ts` que mostra o método `create` do nosso `ProdutoService` sendo utilizado:

```typescript
@Component({
  standalone: true,
  selector: 'jhi-produto-update',
  templateUrl: './produto-update.component.html',
  imports: [SharedModule, FormsModule, ReactiveFormsModule],
})
export class ProdutoUpdateComponent implements OnInit {

  protected produtoService = inject(ProdutoService);

  ...
  save(): void {
    this.isSaving = true;
    const produto = this.produtoFormService.getProduto(this.editForm);
    if (produto.id !== null) {
      this.subscribeToSaveResponse(this.produtoService.update(produto));
    } else {
      this.subscribeToSaveResponse(this.produtoService.create(produto));
    }
  }
...
```

# Interceptador

Mais um treco que não vai assustar nenhum Dev do back, afinal, é só código também. Um interceptador tem o papel de interceptar e modificar requisições HTTP, tem função semelhante a dos _filters_ da API Servlet do Java.

Com um interceptor, você pode por exemplo, inserir um cabeçalho Authorization em todas as requisições destinadas aos endpoints do backend. Se você abrir o interceptador `app/core/interceptor/auth-interceptor.ts`, vai constatar que é exatamente isso que ele está fazendo na implementação do método `intercept`:

```typescript
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private stateStorageService = inject(StateStorageService);
  private applicationConfigService = inject(ApplicationConfigService);

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const serverApiUrl = this.applicationConfigService.getEndpointFor('');
    if (!request.url || (request.url.startsWith('http') && !(serverApiUrl && request.url.startsWith(serverApiUrl)))) {
      return next.handle(request);
    }

    const token: string | null = this.stateStorageService.getAuthenticationToken();
    if (token) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`,
        },
      });
    }
    return next.handle(request);
  }
}
```

# Rota

Uma rota define como o Angular responderá a diferentes URLs. Em outras palavras, uma rota define qual componente Angular será apresentado para um caminho de URL específico. Simples assim!

```typescript
const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
  },
  {
    path: 'login',
    component: LoginComponent,
  },
];
```

No exemplo acima, quando o usuário digitar no navegador `http://localhost:4200/`, o componente exibido pelo Angular será o `HomeComponent`. Já quando ele digitar ou for redirecionado para `http://localhost:4200/login`, é o `LoginComponent` que será exibido na interface do usuário.

Além de declarar as rotas da aplicação, elas precisam ser registradas para que a aplicação tenha o comportamento esperado.

As rotas que coloquei acima como exemplo estão declaradas da forma mais simples possível. Uma rota pode ser bem mais complexa que isso, ela pode por exemplo:

- definir dados a serem enviados para o componente especificado na rota;
- carregar outro conjunto de rotas dinamicamente;
- implementar lógica a ser executada antes do carregamento do componente da rota. Por exemplo, para validar se o usuário tem as roles de acesso necessárias;
- implementar lógica a ser executada antes de sair do componente da rota. Por exemplo, para pedir uma confirmação do usuário caso ele esteja abandonando um formulário no meio de uma edição sem salvar os dados.

Enfim … uma rota nos dá muitas possibilidades, mas acho que para a nano introdução do Angular à turma do backend que pretendíamos, podemos parar por aqui antes de causarmos uma repulsa indesejada rs

Mas se você chegou até aqui e ficou interessado em se aprofundar mais no assunto, o que não falta é gente gabaritada por aí ensinando Angular, até mesmo de graça. E, na boa? Aprender nunca é demais. Ainda que você não tenha intenção de (re)direcionar a sua carreira para o frontend, o conhecimento sobre o framework vai agregar muito na sua interação com os colegas responsáveis por esse nicho nos seus projetos.

Duas fontes que me ajudaram a entender melhor esse mundo (sim, apenas entender, eu não fui convertido rsrs) foram: [o canal da Loiane Groner no YouTube](https://www.youtube.com/@loianegroner) e a [Formação Angular na Alura](https://www.alura.com.br/formacao-angular-14). Sem falar, claro, nos próprios canais oficiais do Angular: o [blog](https://blog.angular.io/) e o [canal no YouTube](https://www.youtube.com/@Angular).