feat: implement CRUD for Servers

master
Artur Oliveira 2025-12-15 18:02:52 -03:00
parent 354f8d1d42
commit 9e44e365ab
7 changed files with 442 additions and 2 deletions

View File

@ -1,7 +1,7 @@
{
"info": {
"name": "Users API - Server Manager",
"description": "Collection de testes para a API de Usuários",
"name": "Server Manager API",
"description": "Collection de testes para a API de Usuários e Servidores",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
@ -214,6 +214,209 @@
"response": []
}
]
},
{
"name": "Servers",
"item": [
{
"name": "Create Server",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Production DB Server\",\n \"ip\": \"192.168.1.100\",\n \"port\": 5432,\n \"user\": \"admin\",\n \"password\": \"admin123\",\n \"type\": \"PRODUCTION\",\n \"application\": \"DATABASE\",\n \"dbType\": \"POSTGRESQL\"\n}"
},
"url": {
"raw": "{{base_url}}/api/servers",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers"
]
}
},
"response": []
},
{
"name": "Create Server - Test 2",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Dev MySQL Server\",\n \"ip\": \"192.168.1.101\",\n \"port\": 3306,\n \"user\": \"root\",\n \"password\": \"root123\",\n \"type\": \"DEVELOPMENT\",\n \"application\": \"DATABASE\",\n \"dbType\": \"MYSQL\"\n}"
},
"url": {
"raw": "{{base_url}}/api/servers",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers"
]
}
},
"response": []
},
{
"name": "Get All Servers",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers"
]
}
},
"response": []
},
{
"name": "Get Server by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers/{{server_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"{{server_id}}"
]
}
},
"response": []
},
{
"name": "Get Server by Name",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers/name/Production DB Server",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"name",
"Production DB Server"
]
}
},
"response": []
},
{
"name": "Get Servers by Type",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers/type/PRODUCTION",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"type",
"PRODUCTION"
]
}
},
"response": []
},
{
"name": "Get Servers by Application",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers/application/DATABASE",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"application",
"DATABASE"
]
}
},
"response": []
},
{
"name": "Update Server",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Production DB Server Updated\",\n \"ip\": \"192.168.1.100\",\n \"port\": 5432,\n \"user\": \"admin\",\n \"password\": \"newpassword123\",\n \"type\": \"PRODUCTION\",\n \"application\": \"DATABASE\",\n \"dbType\": \"POSTGRESQL\"\n}"
},
"url": {
"raw": "{{base_url}}/api/servers/{{server_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"{{server_id}}"
]
}
},
"response": []
},
{
"name": "Delete Server",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/servers/{{server_id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"servers",
"{{server_id}}"
]
}
},
"response": []
}
]
}
],
"variable": [
@ -226,6 +429,11 @@
"key": "user_id",
"value": "",
"type": "string"
},
{
"key": "server_id",
"value": "",
"type": "string"
}
]
}

View File

@ -0,0 +1,63 @@
package com.hitcommunications.servermanager.controllers;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.ServersType;
import com.hitcommunications.servermanager.services.ServersService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/servers")
@RequiredArgsConstructor
public class ServersController {
private final ServersService serversService;
@PostMapping
public ResponseEntity<ServerDTO> create(@RequestBody @Valid NewServerDTO createDTO) {
return ResponseEntity.ok().body(serversService.create(createDTO));
}
@GetMapping("/{id}")
public ResponseEntity<ServerDTO> getById(@PathVariable String id) {
return ResponseEntity.ok().body(serversService.getById(id));
}
@GetMapping("/name/{name}")
public ResponseEntity<ServerDTO> getByName(@PathVariable String name) {
return ResponseEntity.ok().body(serversService.getByName(name));
}
@GetMapping("/type/{type}")
public ResponseEntity<List<ServerDTO>> getByType(@PathVariable ServersType type) {
return ResponseEntity.ok().body(serversService.getByType(type));
}
@GetMapping("/application/{application}")
public ResponseEntity<List<ServerDTO>> getByApplication(@PathVariable Applications application) {
return ResponseEntity.ok().body(serversService.getByApplication(application));
}
@GetMapping
public ResponseEntity<List<ServerDTO>> getAll() {
return ResponseEntity.ok().body(serversService.getAll());
}
@PutMapping("/{id}")
public ResponseEntity<ServerDTO> update(@PathVariable String id, @RequestBody @Valid NewServerDTO updateDTO) {
return ResponseEntity.ok().body(serversService.update(id, updateDTO));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable String id) {
serversService.delete(id);
return ResponseEntity.noContent().build();
}
}

View File

@ -0,0 +1,22 @@
package com.hitcommunications.servermanager.mappers;
import com.hitcommunications.servermanager.model.Servers;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import java.util.List;
@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface ServersMapper {
Servers toEntity(NewServerDTO createDTO);
ServerDTO toDTO(Servers entity);
List<ServerDTO> toDTO(List<Servers> entities);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
Servers partialUpdate(NewServerDTO updateDTO, @MappingTarget Servers entity);
}

View File

@ -0,0 +1,20 @@
package com.hitcommunications.servermanager.model.dtos;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
public record NewServerDTO(
@NotBlank String name,
@NotBlank String ip,
@NotNull Integer port,
@NotBlank String user,
@NotBlank String password,
@NotNull ServersType type,
@NotNull Applications application,
@NotNull DatabaseType dbType
) {
}

View File

@ -0,0 +1,22 @@
package com.hitcommunications.servermanager.model.dtos;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.DatabaseType;
import com.hitcommunications.servermanager.model.enums.ServersType;
import java.sql.Timestamp;
public record ServerDTO(
String id,
String name,
String ip,
Integer port,
String user,
ServersType type,
Applications application,
DatabaseType dbType,
Timestamp createdAt,
Timestamp updatedAt
) {
}

View File

@ -0,0 +1,17 @@
package com.hitcommunications.servermanager.repositories;
import com.hitcommunications.servermanager.model.Servers;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.ServersType;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface ServersRepository extends JpaRepository<Servers, String> {
Optional<Servers> findByName(String name);
List<Servers> findByType(ServersType type);
List<Servers> findByApplication(Applications application);
Optional<Servers> findByIpAndPort(String ip, Integer port);
}

View File

@ -0,0 +1,88 @@
package com.hitcommunications.servermanager.services;
import com.hitcommunications.servermanager.mappers.ServersMapper;
import com.hitcommunications.servermanager.model.Servers;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO;
import com.hitcommunications.servermanager.model.enums.Applications;
import com.hitcommunications.servermanager.model.enums.ServersType;
import com.hitcommunications.servermanager.repositories.ServersRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ServersService {
private final ServersMapper mapper;
private final ServersRepository repo;
public ServerDTO create(NewServerDTO createDTO) {
// Check if server with same IP and port already exists
repo.findByIpAndPort(createDTO.ip(), createDTO.port()).ifPresent(entity -> {
throw new RuntimeException("Server already exists with IP: " + createDTO.ip() + " and port: " + createDTO.port());
});
Servers entity = mapper.toEntity(createDTO);
entity = repo.save(entity);
return mapper.toDTO(entity);
}
public ServerDTO getById(String id) {
return repo.findById(id)
.map(mapper::toDTO)
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
}
public ServerDTO getByName(String name) {
return repo.findByName(name)
.map(mapper::toDTO)
.orElseThrow(() -> new RuntimeException("Server not found with name: " + name));
}
public List<ServerDTO> getByType(ServersType type) {
return repo.findByType(type)
.stream()
.map(mapper::toDTO)
.toList();
}
public List<ServerDTO> getByApplication(Applications application) {
return repo.findByApplication(application)
.stream()
.map(mapper::toDTO)
.toList();
}
public List<ServerDTO> getAll() {
return repo.findAll()
.stream()
.map(mapper::toDTO)
.toList();
}
public ServerDTO update(String id, NewServerDTO updateDTO) {
Servers entity = repo.findById(id)
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
// Check if IP/port combination already exists (excluding current server)
repo.findByIpAndPort(updateDTO.ip(), updateDTO.port()).ifPresent(existingServer -> {
if (!existingServer.getId().equals(id)) {
throw new RuntimeException("Server already exists with IP: " + updateDTO.ip() + " and port: " + updateDTO.port());
}
});
mapper.partialUpdate(updateDTO, entity);
entity = repo.save(entity);
return mapper.toDTO(entity);
}
public void delete(String id) {
if (!repo.existsById(id)) {
throw new RuntimeException("Server not found with id: " + id);
}
repo.deleteById(id);
}
}