Desenvolvimento Web - Front End - Aula 06
Desenvolvimento Web - Front End - Aula 06
FRONT-END
AULA 6
1.1 JWT
2
uma biblioteca ou cliente HTTP disponível para a linguagem de
programação escolhida e aprenda a utilizá-la.
• Realize as solicitações HTTP: com a biblioteca ou cliente HTTP
configurado, você pode começar a fazer solicitações à API. Isso
geralmente envolve construção de uma solicitação HTTP (como GET,
POST, PUT, DELETE) com os parâmetros e cabeçalhos adequados,
envio da solicitação para a URL da API e tratamento da resposta
retornada.
• Analise a resposta: ao receber a resposta da API, você precisa analisar
os dados retornados e extrair as informações relevantes para o seu
aplicativo. Isso pode envolver a leitura e a manipulação de dados em
formato JSON, XML ou outro formato definido pela API.
• Lide com erros e exceções: durante o consumo da API, é importante lidar
com erros e exceções. Isso inclui tratar códigos de status HTTP não
esperados, erros de autenticação, limites de taxa, entre outros. Certifique-
se de implementar a lógica adequada para lidar com essas situações e
fornecer mensagens de erro adequadas aos usuários do seu aplicativo.
• Teste e itere: à medida que você consome a API, é fundamental testar
todas as funcionalidades e garantir que os dados estejam sendo
recuperados e manipulados corretamente. Faça testes abrangentes para
identificar possíveis problemas ou erros. Se necessário, faça iterações no
código para melhorar a integração com a API.
o 400 Bad Request: indica que a solicitação do cliente não pôde ser
entendida ou foi malformada.
o 401 Unauthorized: indica que o cliente não está autorizado a acessar
o recurso solicitado.
3
o 404 Not Found: indica que o recurso solicitado não foi encontrado no
servidor.
2.1 POST
{
"nome": "João da Silva",
"email": "joao@example.com",
4
"idade": 30
}
2.2 PUT
{
"nome": "João da Silva",
"email": "joao.silva@example.com",
"idade": 31
}
2.3 DELETE
5
ao enviar uma solicitação DELETE para "/api/usuarios/1", estamos solicitando
que o servidor remova o usuário com o ID 1 do banco de dados ou do
armazenamento correspondente.
É importante notar que o uso correto dos métodos HTTP é fundamental
para seguir os princípios do design RESTful e garantir que as operações de sua
aplicação web sejam realizadas de forma consistente e semântica. Além disso,
é importante garantir que as operações de atualização e exclusão sejam
protegidas com autenticação e autorização adequadas, para evitar que usuários
não autorizados realizem essas ações.
Bem, para nosso projeto, temos de tomar algumas atitudes que o tornam
o código mais legível. Primeiramente, do lado da API temos uma classe que
reflete a entidade do banco (está em nosso projeto, consta aqui para
entendimento, pode ser copiada para um componente).
import { Entity, PrimaryGeneratedColumn, Column } from
"typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
age: number;
Para constar:
6
• @Entity(): esta decoradora é usada acima da classe User e indica que
essa classe representa uma entidade de banco de dados. Cada instância
dessa classe representará uma linha na tabela correspondente no banco
de dados.
• @PrimaryGeneratedColumn(): esta decoradora é usada acima da
propriedade id e indica que essa coluna é a chave primária da tabela.
Além disso, é configurada para que seja gerada automaticamente.
Para essa entidade, que reflete o banco, temos de ter alguém que a
controle, que a comande, o que chamamos de controlador, conforme segue:
import { NextFunction, Request, Response } from "express"
import { User } from "../entity/User"
import { AppDataSource } from "../data-source"
7
objetos Request, Response e NextFunction do Express, usados para
manipular as requisições HTTP.
• import { User } from "../entity/User";: esta importação traz a classe User
da entidade (model) definida no arquivo "../entity/User.ts". A classe User
representa o modelo de dados do usuário no aplicativo.
• import { AppDataSource } from "../data-source";: esta importação traz a
classe AppDataSource do arquivo "../data-source.ts". Supõe-se que esta
classe forneça um acesso à fonte de dados, como a conexão com o banco
de dados, por meio do TypeORM.
• private userRepository = AppDataSource.getRepository(User);: esta linha
declara uma propriedade privada chamada userRepository e a inicializa
com o repositório (classe do TypeORM) associado à entidade User. A
classe AppDataSource é usada para obter esse repositório.
• async all(request: Request, response: Response, next: NextFunction) { ...
}: este é um método assíncrono chamado all, que trata a rota para buscar
todos os usuários. Quando essa rota é acessada (por exemplo, usando
um método GET em "/users"), o método all é chamado para responder
com todos os usuários do banco de dados.
• async one(request: Request, response: Response, next: NextFunction) {
... }: este é um método assíncrono que trata a rota para buscar um usuário
específico. Quando essa rota é acessada (por exemplo, usando um
método GET em "/users/1"), o método one é chamado para responder
com os detalhes do usuário cujo ID é fornecido nos parâmetros da URL.
• async save(request: Request, response: Response, next: NextFunction) {
... }: este é um método assíncrono chamado save, que trata a rota para
criar ou atualizar um usuário. Quando essa rota é acessada (por exemplo,
usando um método POST ou PUT em "/users"), o método save é chamado
para criar um novo usuário com os dados fornecidos no corpo da
requisição (request.body), ou atualizar um usuário existente com esses
dados.
• async remove(request: Request, response: Response, next:
NextFunction) { ... }: este é um método assíncrono chamado remove, que
trata a rota para excluir um usuário. Quando essa rota é acessada (por
exemplo, usando um método DELETE em "/users/1"), o método remove
8
é chamado para excluir o usuário cujo ID é fornecido nos parâmetros da
URL.
• method: o método HTTP que a rota suporta, como "get", "post" ou "delete".
• route: a URL associada à rota, por exemplo "/users" ou "/users/:id" (com
um parâmetro de ID).
• controller: o controlador que será responsável por lidar com as
solicitações para essa rota, no caso o UserController.
9
• action: o método do controlador que será invocado quando a rota for
acessada. Por exemplo, "all" chamará o método all do UserController,
"one" chamará o método one, e assim por diante.
@Injectable({
providedIn: 'root'
})
export class HttpService {
constructor(
private http: HttpClient) {
if (!header) {
10
header = new HttpHeaders();
}
return header;
}
11
public delete(url: string): Promise<IResultHttp> {
const header = this.createHeader();
console.log("antes")
console.log(url)
return new Promise(async (resolve) => {
try {
const res = await this.http.delete(url, { headers: header
}).toPromise();
resolve({ success: true, data: res, error: undefined });
} catch (error) {
resolve({ success: false, data: {}, error });
}
});
}
constructor(
public url: string,
public http: HttpService) {
this.urlBase = `${environment.url_api}/${this.url}`;
}
14
}
15
Em resumo, a classe BaseService<T> fornece uma base comum para
outros serviços que precisam fazer requisições HTTP para uma API. Ela utiliza
a propriedade urlBase para armazenar a URL completa da API (que inclui a URL
base da API definida em environment.url_api mais a parte específica do serviço).
Isso permite que os serviços que estendem BaseService possam realizar
requisições HTTP de forma mais fácil e consistente, aproveitando a URL base
da API configurada de forma centralizada.
Agora podemos criar nosso serviço para expor na tela:
import { UsuarioModel } from './../model/usuarioModel';
import { Injectable } from '@angular/core';
import { BaseService } from '../base/base.service';
import { HttpService } from './http.service';
import { IResultHttp } from '../interfaces/IResultHttp';
import { environment } from './../../environments/environment';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UsuarioService extends BaseService<UsuarioModel> {
16
• import { BaseService } from '../base/base.service';: esta linha de código
importa a classe BaseService do arquivo base.service.ts. Como vimos em
um código anterior, BaseService é uma classe abstrata que fornece uma
base comum para serviços que fazem requisições HTTP para uma API.
• import { HttpService } from './http.service';: esta linha de código importa a
classe HttpService do arquivo http.service.ts. Presumivelmente,
HttpService é um serviço personalizado que realiza requisições HTTP.
• import { IResultHttp } from '../interfaces/IResultHttp';: esta linha de código
importa a interface IResultHttp do arquivo IResultHttp.ts, que define a
estrutura dos resultados das requisições HTTP.
• import { environment } from './../../environments/environment';: esta linha
de código importa o objeto environment do arquivo environment.ts, que
contém variáveis de ambiente do Angular, como URLs de API,
dependendo do ambiente em que o aplicativo está sendo executado.
• import { Observable, Subject } from 'rxjs';: esta linha de código importa as
classes Observable e Subject do RxJS. Observable é usada para
trabalhar com fluxos de dados assíncronos, enquanto Subject é um tipo
de Observable que permite emitir e ouvir eventos.
• @Injectable({ providedIn: 'root' }): este é o decorador Injectable aplicado
à classe UsuarioService. O parâmetro { providedIn: 'root' } indica que o
Angular deve criar uma única instância compartilhada de UsuarioService
em todo o aplicativo (singleton).
• export class UsuarioService extends BaseService<UsuarioModel> { ... }:
esta é a declaração da classe UsuarioService, que estende a classe
abstrata BaseService<UsuarioModel>. Isso significa que UsuarioService
herda as características de BaseService, incluindo a propriedade urlBase
e os métodos para fazer requisições HTTP.
• private loginSubject = new Subject<boolean>();: esta linha declara uma
propriedade privada chamada loginSubject, que é um objeto do tipo
Subject<boolean>. Esse objeto Subject será usado para emitir eventos
relacionados ao login.
• constructor(public override http: HttpService) { ... }: este é o construtor da
classe UsuarioService, executado quando uma instância de
UsuarioService é criada. Ele recebe um parâmetro chamado http, que é
do tipo HttpService. A palavra-chave public override é usada para indicar
17
que a propriedade http é uma propriedade herdada de BaseService, que
está sendo substituída (override) na classe UsuarioService.
• Dentro do construtor, a classe super('users', http); é chamada, passando
a string 'users' como o primeiro argumento e o objeto http como o segundo
argumento. A chamada para super() invoca o construtor da classe
BaseService, garantindo que a propriedade urlBase seja configurada
corretamente.
• login(email: string, password: string): Promise<IResultHttp> { ... }: este é
um método chamado login que recebe dois parâmetros email e password
(ambos do tipo string). O método retorna uma promessa (Promise) que
resolve com um objeto do tipo IResultHttp.
@Component({
selector: 'app-usuarios',
18
templateUrl: './usuarios.component.html',
styleUrls: ['./usuarios.component.scss']
})
ngOnInit() {
this.bind();
}
async bind() {
console.log("inicio")
const usuarios = await this.usuarioSrv.GetAll();
console.log ("----");
console.log(usuarios);
console.log ("----");
this.dataSource = new MatTableDataSource(usuarios.data);
}
19
interface que contém o método ngOnInit(),executado após a inicialização
do componente.
• import { UsuarioService } from '../../services/usuario.service';: esta linha de
código importa o serviço UsuarioService do arquivo usuario.service.ts,
que provavelmente é responsável por lidar com as operações
relacionadas aos usuários.
• import { UsuarioModel } from '../../model/usuarioModel';: esta linha de
código importa a classe UsuarioModel do arquivo usuarioModel.ts, que
provavelmente é uma representação do modelo de dados para usuários.
• import { MatFormFieldModule } from '@angular/material/form-field';: esta
linha de código importa o módulo MatFormFieldModule do Angular
Material, que é usado para criar campos de formulário estilizados.
• import { IUsuario } from '../../interfaces/IUsuario';: esta linha de código
importa a interface IUsuario do arquivo IUsuario.ts, que provavelmente
define a estrutura de um usuário.
• import { MatTableDataSource } from '@angular/material/table';: esta linha
de código importa a classe MatTableDataSource do Angular Material, que
é usada para representar a origem dos dados de uma tabela.
• import { Router, ActivatedRoute } from '@angular/router';: esta linha de
código importa as classes Router e ActivatedRoute do Angular, usadas
para lidar com navegação e acesso a parâmetros de rota.
• @Component({ ... }): este é o decorador Component, aplicado à classe
UsuariosComponent, que define o comportamento do componente.
• selector: 'app-usuarios', ...: o seletor do componente é definido como 'app-
usuarios', o que significa que o componente pode ser usado em templates
usando a tag <app-usuarios></app-usuarios>.
• templateUrl: './usuarios.component.html', ...: o arquivo de template do
componente é definido como usuarios.component.html, que
provavelmente contém a marcação HTML para a exibição da lista de
usuários.
• styleUrls: ['./usuarios.component.scss'] ...: o arquivo de estilo do
componente é definido como usuarios.component.scss, que
provavelmente contém os estilos CSS para o componente.
• columns: string[] = ['id', 'Nome', 'Sobrenome'];: esta linha declara um array
de strings chamado columns, que define as colunas a serem exibidas na
20
tabela de usuários. As colunas são identificadas pelos seus nomes (id,
Nome e Sobrenome).
• dataSource!: MatTableDataSource<IUsuario>;: esta linha declara uma
propriedade chamada dataSource, que é uma instância de
MatTableDataSource<IUsuario>, que representa a origem dos dados da
tabela de usuários.
• constructor(private usuarioSrv: UsuarioService, ... ) { ... }: este é o
construtor do componente UsuariosComponent, executado quando uma
instância do componente é criada. Ele recebe três parâmetros injetados:
usuarioSrv (uma instância de UsuarioService), router (uma instância de
Router) e active (uma instância de ActivatedRoute).
• ngOnInit() { this.bind(); }: este é o método ngOnInit da classe
UsuariosComponent, executado após a inicialização do componente. Ele
chama o método bind() para carregar os usuários na tabela ao iniciar o
componente.
• async bind() { ... }: este é o método bind da classe UsuariosComponent,
responsável por carregar os usuários e atualizar a tabela. Ele utiliza o
serviço UsuarioService para obter todos os usuários e, em seguida, cria
uma nova instância de MatTableDataSource com os dados dos usuários
para atualizar a tabela.
• async delete(usuario: UsuarioModel): Promise<void> { ... }: este é o
método delete da classe UsuariosComponent, executado quando o
usuário seleciona a opção de excluir um usuário na tabela. Recebe um
parâmetro usuario (uma instância de UsuarioModel), que representa o
usuário a ser excluído. O método utiliza o serviço UsuarioService para
excluir o usuário, e depois chama o método bind() para atualizar a tabela
após a exclusão. Em seguida, ele navega para a página `/ (a inicial).
21
• Use verbos HTTP corretos para cada ação: GET (para ler dados), POST
(para criar novos recursos), PUT/PATCH (para atualizar recursos
existentes) e DELETE (para excluir recursos).
• Utilize substantivos plurais nas URLs para representar coleções de
recursos (por exemplo, "/usuarios") e identificadores únicos para recursos
individuais (por exemplo, "/usuarios/1").
• Use códigos de status HTTP apropriados para indicar o resultado da
operação (por exemplo, 200 OK para sucesso, 201 Created para criação
bem-sucedida, 404 Not Found para recurso não encontrado etc.).
• Faça uso de filtros, ordenação e paginação para lidar com grandes
conjuntos de dados e melhorar a performance.
• Utilize versionamento na API para garantir a compatibilidade com versões
anteriores ao realizar atualizações.
22
• Utilize serviços para compartilhar lógica de negócio e dados entre
componentes.
• Use o conceito de Observables e Reactive Programming para lidar com
eventos assíncronos e comunicação entre componentes.
• Faça tratamento adequado de erros e exceções, para fornecer uma
experiência de usuário melhor.
• Implemente testes unitários e de integração para garantir a qualidade do
código.
23
• Utilize transações: se necessário, utilize transações para garantir a
consistência dos dados em operações que envolvam múltiplas alterações.
24
3.4 Angular (Framework de Desenvolvimento Web)
25
envolve verificar se o usuário possui uma função específica ou
permissões necessárias para acessar a rota.
• Lazy loading de módulos: ao usar o recurso de carregamento tardio
(lazy loading) de módulos, você pode proteger rotas carregando módulos
apenas quando um usuário tem permissão para acessá-los. Isso ajuda a
reduzir o tamanho inicial da aplicação e permite um controle mais granular
sobre o acesso às rotas.
• Interceptors: são usados para interceptar e modificar solicitações HTTP
antes que elas sejam enviadas ao servidor. Você pode usar um interceptor
para adicionar informações de autenticação, como tokens de acesso, a
cada solicitação. Isso ajuda a garantir que apenas usuários autenticados
possam acessar os recursos do servidor.
26
isso, é comum usar mocks (simulações) ou stubs (imitações) de
dependências externas.
• Cobertura abrangente: os testes unitários devem cobrir várias situações
e cenários possíveis para a unidade de código em questão. Isso inclui
testar diferentes caminhos de execução, valores de entrada e resultados
esperados. A cobertura abrangente ajuda a identificar erros e garantir um
código mais robusto.
• Automação: os testes unitários devem ser automatizados, o que significa
que eles podem ser executados repetidamente sem intervenção manual.
Isso permite que eles sejam facilmente executados durante o
desenvolvimento, com integração contínua ou em uma pipeline de entrega
contínua. A automação dos testes ajuda a reduzir o tempo e os esforços
necessários para validar a funcionalidade do código.
• Frameworks e ferramentas: existem diversos frameworks e ferramentas
disponíveis para facilitar a criação e a execução de testes unitários em
várias linguagens de programação. Alguns exemplos populares são o
JUnit para Java, o pytest para Python e o NUnit para .NET. Essas
ferramentas fornecem recursos para estruturar, organizar e executar os
testes de forma eficiente.
• Integração contínua: os testes unitários são uma parte importante de
uma estratégia de integração contínua, na qual o código é testado
regularmente e de forma automatizada à medida que é desenvolvido. A
integração contínua ajuda a identificar problemas de forma precoce,
promovendo a entrega de software de maior qualidade e reduzindo os
riscos de regressão.
27
armazenamento, bancos de dados, redes, software e outros recursos, por meio
da internet. Em vez de uma empresa possuir e manter fisicamente esses
recursos, eles são fornecidos por provedores de serviços de nuvem, como
Amazon Web Services (AWS), Microsoft Azure e Google Cloud Platform (GCP).
Os serviços de nuvem podem ser divididos em três modelos principais:
5.3 Deploy
29
É preciso então acessar uma conta da Amazon, para uso do Amazon S3.
Anote as credenciais de acesso (chave de acesso e chave secreta) associadas
a essa conta. Essas informações serão usadas para autenticar o upload.
Instale a AWS CLI (Command Line Interface), seguindo as instruções no
site oficial da AWS: <https://aws.amazon.com/cli/>.
Execute o comando aws. Configure no terminal e insira as credenciais de
acesso (chave de acesso e chave secreta), além da região padrão.
No terminal, navegue até a pasta "dist" do seu projeto Angular, onde os
arquivos de produção foram gerados. Use o seguinte comando para fazer o
upload dos arquivos para o bucket do Amazon S3:
aws s3 sync . s3://nome-do-seu-bucket
FINALIZANDO
30
TypeScript para fornecer tipagem estática, o que traz vantagens para o
desenvolvimento, como aproveitamento do sistema de módulos para
modularizar o código. O ciclo de vida dos componentes permitiu controlar o
comportamento durante as etapas de inicialização, atualização e destruição do
componente.
Ao finalizar o desenvolvimento, a página web foi implantada em um
servidor para que os usuários possam acessá-la pela internet. Tecnicamente,
cumprimos nosso percurso, mas muito depende de interesse e aprofundamento
individual.
Sucesso!
31