Como implementar isso no Back-End?
E aí, pessoal, tudo bem? Bem, vou ser sincero em dizer que estou desenvolvendo uma nova implementação que jamais fiz antes e, por isso, estou pesquisando bastante e até perguntando em fóruns para os mais experientes. Por exemplo, um projeto simples, onde um cliente possui muitos endereços, mas um endereço pertence a apenas um único cliente.
Vamos aos exemplos: No banco de dados, há dois clientes:
{
Id: 1,
Username: "Clark Kent",
Password: "Admin799"
}
{
Id: 2,
Username: "Maite Perroni",
Password: "Common999"
}
O primeiro cliente, "Clark Kent", será o administrador do sistema, ou seja, poderá manipular todo o sistema, permitindo adicionar novos clientes, listar todos e apagar. O segundo cliente, "Maite Perroni", será uma conta comum, ou seja, poderá manipular apenas os seus próprios relacionamentos, entre eles, adicionar um novo endereço, listar todos, atualizar e excluir.
Bem, conforme os exemplos, podemos dizer que os clientes já foram criados e fizeram login em suas respectivas contas, certo? Agora, como eu poderia implementar o caso em que o cliente "Clark Kent" deseja adicionar um novo endereço à sua conta, mas o endereço no banco de dados ficou nulo e não referenciou a conta do cliente que foi adicionado, por exemplo:
Id | Username | Password
1 | ClarkKent | Admin799
Id | Email | Número | Client_Id
1 | ClarkKent@ | 2932183129 | null
Estou muito confuso com isso, pois minha única lógica e saída realmente é desenvolver um serviço: ClienteAddressService, que terá cada método CRUD. Vamos dar o exemplo do save:
public void createClienteAddress(int clientId, Address address) {
// Primeiro, vai buscar no repositório para verificar se o clientId existe.
// Caso exista, vai vincular o address à conta do cliente.
// Também vai vincular o id do cliente na tabela de Address.
}
Assim, como funcionaria uma criação de ClienteAddressController, por exemplo:
@Route("/clients/addresses")
@Request("/clientId/addressId")
public void createClienteAddress(int clientId, Address address) {}
Sem dizer que após isso, irei implementar segurança e autorização. Está correta a minha lógica? Aceitaria muito ajuda.
Tanto o service e o controller ficou assim, conforme a lógica que tive:
SERVICE:
@Service
@AllArgsConstructor
public class UserAddressService {
private final UserService userService;
private final AddressService addressService;
public void save(UUID userId, Address address) {
var existUser = userService.getById(userId);
existUser.getAddresses().add(address);
address.setUserId(existUser.getId());
addressService.save(address);
}
public Optional<Address> getById(UUID userId, UUID addressId) {
var existUser = userService.getById(userId);
var existAddress = addressService.getById(addressId);
return existUser.getAddresses().stream()
.filter(id -> id.getId() == existAddress.getId())
.findFirst();
}
}
CONTROLLER:
@RestController
@RequestMapping("/users/addresses")
@AllArgsConstructor
public class UserAddressController {
private final UserAddressService service;
@PostMapping("/{userId}")
public ResponseEntity<Address> save(@PathVariable UUID userId, @RequestBody Address address) {
var savedAddress = service.save(userId, address);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(savedAddress);
}
@GetMapping("/{userId/{addressId}")
public ResponseEntity<Address> getById(@PathVariable UUID userId, UUID addressId) {
var existAddress = service.getById(userId, addressId);
return ResponseEntity
.status(HttpStatus.OK)
.body(existAddress.get());
}
}
Se a relação do Usuário com o Endereço é 1:N (um usuário pode ter múltiplos endereços), então a sua tabela de endereços deve conter um constraint de uma chave estrangeira (pesquise como fazer isso com base no banco que estiver utilizando), assim o banco irá garantir que a coluna contendo o id do usuário deve corresponder a uma entrada existente na tabela de usuários.
Outra coisa que notei, é que no seu exemplo a senha está em plain text (se for só um exemplo mesmo e você já souber disso, pode desconsiderar, mas vale a pena falar sobre). Para salvar senhas dos usuários em bancos, é extremamente recomendado que se utilize hash, procurar saber mais sobre isso que é bem importante.
Duas dicas em questão de código:
- Tente manter a conformidade entre a nomenclatura das classes/métodos.
- Há a mistura do português com o inglês, como é o caso de createClienteAddress.
- Em determinado momento, o cliente passa a ser chamado de User, defina qual será a nomenclatura padrão.
- Algumas classes podem ser substituidas por record o que lhe torna possível tirar o @AllArgsConstructor e consequentemente a dependência do Lombok.
Sobre a resolução do caso em si: Parece que a falha está no DDL do Banco de Dados. Só faz sentido existir um endereço se ele está vinculado a um cliente, logo: 1. client_id deverá ser NOT NULL e/ou 2. a Primary Key deve ser uma chave composta com o próprio address_id e o client_id (isso significa que não pode existir um endereço sem um cliente).Tendo resolvido isso, nem será possível adicionar novos registros se não estiverem em conformidade com essas regras e estourará Exception se tentar.
Se este registro tiver sido feito anteriormente e só quer correção, sugiro remover o registro e adicionar novamente OU fazer a inserção manual da edição direto no SQL.
Última dica: Parece que desenhou pouco como vai ser a solução, do que precisa ou não. Não parece nem ter um desenho claro do Banco de Dados, recomendo parar de colocar a mão no código um pouco e desenhar o DER e pelo menos um modelo de UML de como será o fluxo do processo.