Faremos todo o ambiente backend com node + typescript, e para isso, precisaremos baixar as seguintes dependências:
npm i -D typescript sucrase
typescript: linguaguem onde rodaremos nossa aplicação sucrase: vai converter nosso código typescript em javascript de forma muito mais rápida comparado ao Babel
npm i bcryptjs cors express jsonwebtoken mysql2 sequelize multer nodemon dotenv
- bcryptjs: É uma biblioteca para criptografar senhas.
- cors: O CORS é uma sigla para Cross-Origin Resource Sharing, que se refere a uma política de segurança implementada pelos navegadores da web. Essa política restringe solicitações feitas a um domínio diferente do domínio da página que está fazendo a solicitação.
- jsonwebtoken: JSON Web Tokens (JWTs) são uma forma de representar informações de maneira segura entre duas partes. Em resumo, é uma lib usada para criar tokens
- mysql2: É um driver para interagir com bancos de dados MySQL a partir de aplicativos Node.js. Ele permite que você execute consultas SQL em um banco de dados MySQL.
- sequelize: Uma biblioteca ORM que simplifica a interação com bancos de dados relacionais, como MySQL, PostgreSQL, SQLite e outros, através de modelos JavaScript.
- multer: Facilita o upload de arquivos, como imagens e documentos, em seu aplicativo Node.js.
- dotenv: permite ler facilmente variaveis de ambiente
- express-async-errors: O express-async-errors é um pacote Node.js que facilita o tratamento de erros assíncronos em aplicativos Express. Ele permite que você capture exceções assíncronas lançadas em rotas ou middleware e as direcione para o manipulador de erros do Express, em vez de deixá-las serem propagadas e potencialmente quebrarem seu aplicativo.
- nodemon: é um utilitário que monitora as mudanças nos arquivos do seu projeto e reinicia automaticamente o servidor Node. js quando necessário
Vamos criar um arquivo chamado nodemon.json e vamos colocar o seguinte bloco de código:
{
"ext": "ts",
"execMap": {
"ts": "sucrase-node index.ts"
}
}
Agora, no arquivo package.json do backend, vamos alterar apenas esse bloco de código:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon index.ts"
},
npm i --save-dev @types/express @types/bcryptjs @types/jsonwebtoken @types/multer @types/cors
Agora, vamos instalar o mysql-server
sudo apt install -y mysql-server #instala o mysql
sudo mysql_secure_installation # inicia os protocolos de segurança para a instalação do mysql
systemctl status mysql.service # Visualiza se o serviço está mesmo ativo
sudo mysql -u root # Estabelece uma conexão com o MySql
# Uma vez logado
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Ab12345*';
SHOW DATABASES
Depois, vamos criar um banco de dados chamado imagebank
create database imagebank;
Agora estamos pronto para fazer a integração com o sequelize dentro do banco de dados
- controllers: intermediario entre o Model e a View (parecido com os das rotas)
- UserControllers.js: manipulação dos usuários
- ImagesControllers.js: manipulação das imagens
- db: conexão com o banco de dados
- helpers: para funcões sem locais de uso fixo (para ajudar)
- Authenticate.js: arquivo que verifica se existe um token e se ele é válido. Caso seja verdadeiro, dá ao usuário acesso a rotas privadas
- Create-token.js: arquivo que cria um token com base nas informações do usuário e manda para o front-end
- get-token.js: arquivo que retorna os dados do usuário com base no token fornecido
- imagesUpload.js utiliza a biblioteca multer para salvar as imagens
- no inicio do projeto, será usado para salvar localmente, e depois usaremos para salvar as imagens do banco de imagens em um bucket no s3
- imageUserEdit.ts: utiliza a biblioteca multer para salvar imagens do perfil do usuário
- no inicio do projeto, será usado para salvar localmente, e depois usaremos para salvar as imagens do perfil do usuário em um bucket no s3
- deleteImage.ts: esse arquivo possui duas funções, que servem:
- deleteImage: vai deletar uma imagem do banco de imagens do usuário sempre que ele solicitar a exclusão
- deleteImageProfileAfterEdit: vai deletar uma imagem sempre que o usuário trocar a foto de perfil (evitando o acúmulo de imagens não utilizadas)
- models: interação com o banco de dados e com o controllers
- User.js: interação com o banco de dados do usuário (tabela Users)
- Images.js: interação com o banco de dados das imagens (tabela Images)
- routes: conjunto de rotas com base do Controllers
- UserRouter.js: rotas para manipulação dos usuários dentro do banco
- ImagesRoutes.js: rotas para manipulação das imagens dentro do banco de dados
- public: Diretório para salvar imagens
- images: salva todas as imagens, tanto do perfil do usuário, quanto as do banco de imagens
Para o frontend, vamos utilizar o react com a ferramente de construção vite. Primeiro, vamos executar o seguinte comando:
npm create vite@latest
Vamos colocar o nome do nosso arquivo de frontend, escolher o react e depois Typescript. Após isso, vamos executar os seguintes comando:
cd frontend
npm install
npm run dev
- .eslintrc.cjs: é usado em projetos React (e em outros projetos JavaScript) para configurar as regras e as configurações do ESLint. ESLint é uma ótima ferramenta para ajudar a automatizar a padronização do código em nosso projeto. Com ela conseguimos definir regras de padronização, achar códigos fora do padrão e consertá-los automaticamente
- vite.config.ts: esse arquivo é usado para configurar o Vite. Ele pode conter configurações relacionadas a plugins, roteamento, aliases de importação, entre outras coisas.
- tsconfig.json: especifica os arquivos raiz e as configurações de compilação necessárias para o projeto. Projetos JavaScript podem ter um arquivo jsconfig. json , que tem quase o mesmo propósito, mas possui algumas flags do compilador relacionadas ao JavaScript que já estão habilitadas por padrão.
Instalando as bibliotecas de css in js e de manipulação de rotas
npm i styled-components react-router-dom react-hook-form js-cookie react-icons @mui/material @emotion/react @emotion/styled axios
- styled-components: biblioteca para React e React Native que permite que você escreva CSS no JavaScript.
- react-router-dom: biblioteca que permite que você configure rotas em sua aplicação, de modo que diferentes componentes sejam renderizados com base na URL atual. Isso é crucial para criar aplicativos de página única (SPA) e navegação sem recarregamento de página.
- react-hook-form: biblioteca para gerenciamento de formulários em React. Ela permite que você crie formulários flexíveis e complexos com validação integrada.
- js-cookie: js-cookie é uma biblioteca que facilita a leitura e a escrita de cookies no navegador usando JavaScript
Instalando as dependências de TS das bibliotecas
npm i -D @types/styled-components @types/react-router-dom @types/js-cookie
Caso apareça um erro do arquivo tsconfig.json, vamos adcionar a seguinte linha de codígo ao arquivo:
"include": ["src/**/*.ts", "src/**/*.tsx"]
- /: página inicial com imagens
- /login: rota para login
- /register: rota para o registro
- /create: rota para criar images
- /profile: rota que mostra informações do perfil
- /myimages: rota que mostra minhas imagens (podendo editar ou excluir)
- assets: algumas imagens estáticas do projeto
- Componentes: pasta onde fica todos os componentes do projeto
- Api: realiza a chamada da api através da biblioteca axios
- Context:
- Auth.tsx: Arquivo gerenciamento de usuários e de autenticação
- UserContext.tsx: contexto nossa aplicação
- Routes: Pasta onde fica todas as rotas
- Header: estrutura do header (que não muda)
- RoutesPrivates: Rotas privadas que só podem ser acessadas se o token for válido
- Private: realiza a verificação do token e permite o usuário acessar a rota privada (ou não)
- Types: arquivo onde contém as interfaces mais utilizadas
- Utils: arquivo que contém algumas ferramentas que ajudam no projeto
Backend
Primeiro, vamos criar um arquivo de Dockerfile para a criação do container da nossa aplicação node.js.
FROM node:18-alpine
WORKDIR /backend
COPY package*.json ./
RUN npm install -g npm@10.2.0 && npm install
COPY . ./
EXPOSE 3000
CMD [ "npm", "start" ]
Frontend
Agora, vamos criar um arquivo de Dockerfile para a aplicação react
FROM node:18-alpine as build
WORKDIR /app
COPY package*.json ./
RUN npm install -g npm@10.2.0 && npm install
COPY . ./
RUN npm run build
EXPOSE 4000
CMD ["npm","run","dev"]
Antes de criar o arquivo de docker-compose, precisamos realizar uma configuração na aplicação react para poder rodar dentro do container.
Vamos no arquivo vite.config.ts e adcionar a seguinte linha de comando:
export default defineConfig({
plugins: [react()],
server:{
host: true,
strictPort: true,
port: 4000
}
})
Docker compose
Em seguida, vamos criar o docker-compose.yml, onde vamos:
- Construir nossa aplicação node.js (porta 3000)
- Construir o container do mysql (porta 3306 interna e 3307 externa)
- Volume: arquivo db na raiz do projeto, porém não está incluido no repositório
- Construir o container do phpMyAdmin para gerenciamento do banco de dados (porta 1234)
- http://localhost:1234 -> gerenciar o banco de dados pelo browser
- Construir o container da aplicação react (porta 4000)
Agora, vamos executar o seguinte comando:
docker-compose up -d --build ##vai construir os containers e rodar a aplicação
Podemos ver todos os containers rodando com o comando:
docker ps
E podemos visualizar os logs de cada container, e também acessa-los caso necessite:
docker logs hash_container -h #logs do container
docker exec -it hash_container sh #acessar o container por um terminal sh
Para evitar esse erro, vamos no arquivo index.js no backend, e alterar a origin do cors para 'http://localhost'
E, se não resolver, vamos adcionar o seguinte bloco de código:
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost'); // Permitir solicitações do domínio http://localhost
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
Primeiro, vamos criar duas buckets no amazon S3
- a primeira chamada imagebank-profile-user-s3 para salvar a foto de perfil do usuário
- e a segunda chamada imagebank-images-upload-s3 para salvar as imagens feitas por apload
Agora, vamos instalar as seguintes dependências no backend:
npm install @aws-sdk/client-s3 multer-s3
E também a dependência do ts para o multer-s3
npm i -D @types/multer-s3"
-
multer-s3: O multer-s3 é um pacote que estende as funcionalidades do multer para facilitar o upload de arquivos diretamente para o Amazon S3. Ele fornece uma maneira conveniente de configurar o multer para enviar arquivos para um bucket específico no S3, incluindo detalhes como autenticação, permissões de acesso e gerenciamento de metadados dos objetos no S3.
-
@aws-sdk/client-s3: é uma parte do AWS SDK para JavaScript versão 3 (v3) que fornece uma interface para interagir com o serviço Amazon S3 (Simple Storage Service) usando JavaScript moderno e assíncrono, como Promises e async/await.
Agora, vamos criar mais um arquivo no diretório /backend/helpers chamado S3Config, onde vamos colocar a configuração de acesso a AWS (lembrando que é necessário ter um usuário com acesso programático, e informar a chave de acesso e a chave secreta). Depois, vamos editar os arquivos de helpers que realiza o upload local para poder salvar e deletar as imagens nos respectivos buckets.
No console da AWS, vamos nos serviços de RDS e criar um banco de dados:
- Selecionando o free tier
- Selecionando o Mysql
- Colocando o nome como imagebank001
- Colocar a senha como Ab12345*
- Colocar o usuário como root
- habilitar o acesso público Depois, precisaremos editar o arquivo /backend/dn/conn.ts lembrando de passar o Endpoint do RDS como host da aplicação.
Para visualizarmos os dados, podemos executar o seguinte comando no terminal local:
mysql -h nome-do-host-do-rds -u nome-de-usuario -p