[DÚVIDA] - Lidando com imagens no back-end
Eae pessoal, tudo certo ? Estou em dúvida de como abordar um assunto, e gostaria de ouvir a opinião de vocês.
Contexto
Estou fazendo um projeto de estudo utilizando NodeJS, só para treinar algumas coisas que eu nunca fiz. Por exemplo, nos meus projetos anteriores, sempre utilizei o Fastify como framework, algum ORM para lidar com o banco de dados, SQLite, e Javascript. Nesse projeto eu estou utilizando Express, sem nenhum ORM, utilizando Postgresql em um container docker, e Typescript.
Enfim, neste projeto há uma funcionalidade que permite o usuário adicionar produtos, contendo nome, descrição, preço e uma imagem. No Controller desta rota, eu recebo a imagem com o tipo multipart/formdata, salvo ela localmente em uma pasta public/uploads utilizando o Multer (acredito que geralmente isso é armazenado em um storage de terceiro, porém fiz dessa forma pois esse não era o foco), crio uma url com base no nome da imagem + data de upload, e salvo essa url no banco, junto com os outros dados. Esse procedimento de capturar a imagem recebida no body da requisição, validar se ela realmente é uma imagem, validar tamanho, etc. ocorre em um Middleware nessa rota de Adicionar Produto.
Está funcionando normalmente, ele cria a url corretamente, e salva localmente. A rota de deletar um produto também funciona, ele deleta o registro no banco, e remove o arquivo localmente também.
Problema - Editando o produto.
Vou criar uma rota para permitir que o usuário edite um produto. No front-end, o usuário clicaria no botão de editar produto, e seria redirecionado para uma página de formulário, carregando todas as informações do produto em questão, porém habilitando os inputs, permitindo que ele altere tanto os campos de texto, quanto a imagem. No final, ele clicaria em Salvar, que dispararia uma requisição para uma rota /produts/edit/:id, enviando TODAS as informações daquele produto (independente se foram alterados ou não).
Nos campos do tipo texto é ok, visto que é só eu fazer um UPDATE FROM WHERE, porém a questão da imagem está me intrigando um pouco: Se o usuário alterar a imagem do produto, eu iria receber a nova imagem no body, validar igual eu fiz na rota de Adicionar Produto, excluir a imagem "antiga" localmente (eu criei uma função para isso na rota de Deletar, então eu conseguiria reaproveitar), e atualizar a image_url no banco. Agora vem minha dúvida (sim, eu sei que enrolei bastante para chegar nisso kkkkkk desculpa): E se o usuário não alterar a imagem ?
Em um primeiro momento, eu pensei em fazer a mesma coisa como se ele tivesse alterado: Eu teria que excluir a imagem "antiga" localmente, e receber ela novamente no body, a mesma imagem. Mas isso me cheira estranho. Pensei em alguma forma identificar que as imagens são iguais, mas não consegui pensar em uma. Eu poderia verificar pelo nome da imagem, mas se o usuário enviar uma imagem com conteúdo diferente, porém com o mesmo nome, a aplicação rejeitaria.
Eu sei que é uma aplicação de estudo, e que provavelmente neste contexto não haveria problema em deletar e adicionar a mesma imagem, porém como eu disse, isso cheira estranho, e mesmo não trabalhando na área, acredito que não seja feito desse jeito. Gostaria do ponto de vista de vocês sobre como lidar com isso (não precisa ter exemplo em código, só quero uma explicação sobre como abordar.)
Muito obrigado, e um ótimo final de semana.
Você conhece o método HTTP PATCH?
Estou com a impressão de que você está fazendo tudo somente através do método HTTP POST. A evidência pra isso é pela sua rota: /produts/edit/:id. Esse "edit" na rota foge do padrão REST, pois geralmente não utilizamos verbos nas rotas - utilizamos somente substantivos. Para indicar que você quer editar um produto já existente, e diferenciar da rota de criação de produto, geralmente utilizamos os verbos PATCH ou PUT. Veja o seguinte link: https://pt.stackoverflow.com/a/217901/128995
Resumindo, o PUT permite que alteremos a entidade inteira (todos os campos do produto). Enquanto isso, o PATCH permite que alteremos somente alguns campos da entidade (por exemplo, só a foto, ou só o nome, ou o nome e o preço, etc.).
Então me soa que você quer utilizar o método HTTP PATCH, para alterar somente alguns campos. O cliente (front-end) saberá quais campos mudaram e quais não mudaram, e farà a requisição passando somente os campos que foram alterados, com seus novos valores. Então se o usuário não mudou a foto, você não passa o campo da foto, e nada muda.
Você não precisa identificar se as imagens são as mesmas, amigo. Na verdade, você pode fazer da seguinte forma:
Caso a imagem seja obrigatória para o produto, você primeiro checa se ele já possui uma imagem salva ou não e isso define se você irá requerer o preenchimento do input de arquivo.
Caso já tenha, você pode apresentar a imagem existente pro usuário e dar a opção de subir outra para substituir no lugar. Caso não receber nada você simplesmente ignora a parte de upload local e geração de URL e tudo mais, apenas ignora aquele campo e atualiza o restante.
acredito que geralmente isso é armazenado em um storage de terceiro, porém fiz dessa forma pois esse não era o foco
Não, isso é comum ser no proprio host, pq custa menos. Só usam de terceiros quando fica muito grande a quantidade de imagens!
Quanto a edição da imagem,
Vc não precisa mexer na imagem original se o usuário não mudar a imagem! Pq isso agora parece "certo" mas quando tiver muita gente editando, isso vai gerar um problema de banda enorme!
O que eu faria: na edição colocaria uma thumb da imagem original(pra pessoa saber que tem a imagem) e um campo de enviar imagem logo abaixo(ou um botão mudar imagem, quando clicado abre o campo de upload e...). Ou seja, as coisas mudariam só se o usuário enviasse uma nova imagem(apaga a antiga coloca a nova e tal). Caso contrario nada muda no banco de bados e no banco de imagens!
Uma maneira bem simples é salvar o hash da imagem e comparar com o hash da "nova" imagem, mas acredito que uma solução melhor é como o colega sugeriu simplesmente não enviar os dados da imagem todo request!!