US06: Add an owner create endpoint to the API
This commit is contained in:
parent
361a09b082
commit
3d9e918f39
@ -2,12 +2,16 @@ package at.ac.tuwien.sepm.assignment.individual.endpoint;
|
|||||||
|
|
||||||
import at.ac.tuwien.sepm.assignment.individual.endpoint.dto.OwnerDto;
|
import at.ac.tuwien.sepm.assignment.individual.endpoint.dto.OwnerDto;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.endpoint.mapper.OwnerMapper;
|
import at.ac.tuwien.sepm.assignment.individual.endpoint.mapper.OwnerMapper;
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.service.OwnerService;
|
import at.ac.tuwien.sepm.assignment.individual.service.OwnerService;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.util.ValidationException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
@ -36,4 +40,22 @@ public class OwnerEndpoint {
|
|||||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Error during reading owner", e);
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Error during reading owner", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
public OwnerDto addHorse(@RequestBody OwnerDto owner) {
|
||||||
|
LOGGER.info("POST " + BASE_URL);
|
||||||
|
try {
|
||||||
|
Owner ownerEntity = ownerMapper.dtoToEntity(owner);
|
||||||
|
return ownerMapper.entityToDto(ownerService.addOwner(ownerEntity));
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
|
||||||
|
"Error during adding new owner: " + e.getMessage());
|
||||||
|
} catch (DataAccessException e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
throw new ResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
"Something went wrong during the communication with the database");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,7 @@ public class OwnerMapper {
|
|||||||
return new OwnerDto(owner.getId(), owner.getName(), owner.getCreatedAt(), owner.getUpdatedAt());
|
return new OwnerDto(owner.getId(), owner.getName(), owner.getCreatedAt(), owner.getUpdatedAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Owner dtoToEntity(OwnerDto owner) {
|
||||||
|
return new Owner(owner.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,11 @@ public interface OwnerDao {
|
|||||||
*/
|
*/
|
||||||
Owner findOneById(Long id);
|
Owner findOneById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param owner that specifies the owner to add
|
||||||
|
* @return the newly created horse
|
||||||
|
* @throws DataAccessException will be thrown if something goes wrong during the database access.
|
||||||
|
*/
|
||||||
|
Owner addOwner(Owner owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,20 @@ import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
|||||||
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||||
|
import org.springframework.jdbc.support.KeyHolder;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@ -39,6 +45,49 @@ public class OwnerJdbcDao implements OwnerDao {
|
|||||||
return owners.get(0);
|
return owners.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Owner addOwner(Owner owner) {
|
||||||
|
LOGGER.trace("Add owner {}", owner);
|
||||||
|
final String sql = "INSERT INTO " + TABLE_NAME + "(name, created_at, updated_at) VALUES(?,?,?)";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if the constraints are violated
|
||||||
|
this.validateOwner(owner);
|
||||||
|
|
||||||
|
LocalDateTime currentTime = LocalDateTime.now();
|
||||||
|
|
||||||
|
owner.setCreatedAt(currentTime);
|
||||||
|
owner.setUpdatedAt(currentTime);
|
||||||
|
|
||||||
|
// Create a key holder to get the key of the new record
|
||||||
|
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||||
|
|
||||||
|
int changes = jdbcTemplate.update(connection -> {
|
||||||
|
PreparedStatement ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
|
||||||
|
|
||||||
|
ps.setString(1, owner.getName());
|
||||||
|
ps.setObject(2, owner.getCreatedAt());
|
||||||
|
ps.setObject(3, owner.getUpdatedAt());
|
||||||
|
return ps;
|
||||||
|
}, keyHolder);
|
||||||
|
|
||||||
|
if (changes == 0)
|
||||||
|
throw new DataAccessException("Creating owner failed, no rows affected") {};
|
||||||
|
|
||||||
|
owner.setId(((Number)keyHolder.getKeys().get("id")).longValue());
|
||||||
|
|
||||||
|
return owner;
|
||||||
|
|
||||||
|
} catch (DataAccessException e) {
|
||||||
|
// We are doing this in order to not change the exception type
|
||||||
|
throw new DataAccessException("Adding new records failed", e) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateOwner(Owner owner) throws DataIntegrityViolationException {
|
||||||
|
if(owner.getName() == null || owner.getName().isEmpty())
|
||||||
|
throw new DataIntegrityViolationException("Required parameters for owner missing");
|
||||||
|
}
|
||||||
|
|
||||||
private Owner mapRow(ResultSet resultSet, int i) throws SQLException {
|
private Owner mapRow(ResultSet resultSet, int i) throws SQLException {
|
||||||
final Owner owner = new Owner();
|
final Owner owner = new Owner();
|
||||||
|
@ -2,6 +2,8 @@ package at.ac.tuwien.sepm.assignment.individual.service;
|
|||||||
|
|
||||||
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.util.ValidationException;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
|
||||||
public interface OwnerService {
|
public interface OwnerService {
|
||||||
|
|
||||||
@ -14,4 +16,12 @@ public interface OwnerService {
|
|||||||
*/
|
*/
|
||||||
Owner findOneById(Long id);
|
Owner findOneById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param owner to create
|
||||||
|
* @return the new owner
|
||||||
|
* @throws ValidationException will be thrown if something goes wrong during verification.
|
||||||
|
* @throws DataAccessException will be thrown if the horse could not be saved in the database.
|
||||||
|
*/
|
||||||
|
Owner addOwner(Owner owner) throws ValidationException, DataAccessException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@ package at.ac.tuwien.sepm.assignment.individual.service.impl;
|
|||||||
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.service.OwnerService;
|
import at.ac.tuwien.sepm.assignment.individual.service.OwnerService;
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.util.ValidationException;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.util.Validator;
|
import at.ac.tuwien.sepm.assignment.individual.util.Validator;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -29,4 +31,10 @@ public class SimpleOwnerService implements OwnerService {
|
|||||||
return ownerDao.findOneById(id);
|
return ownerDao.findOneById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Owner addOwner(Owner owner) throws ValidationException, DataAccessException {
|
||||||
|
LOGGER.trace("addOwner({})", owner);
|
||||||
|
this.validator.validateNewOwner(owner);
|
||||||
|
return ownerDao.addOwner(owner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ public class Validator {
|
|||||||
|
|
||||||
|
|
||||||
public void validateNewOwner(Owner owner) throws ValidationException {
|
public void validateNewOwner(Owner owner) throws ValidationException {
|
||||||
|
if(owner.getName() == null || owner.getName().isEmpty()) {
|
||||||
|
throw new ValidationException("Required value name missing");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateUpdateOwner(Owner owner) throws ValidationException {
|
public void validateUpdateOwner(Owner owner) throws ValidationException {
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package at.ac.tuwien.sepm.assignment.individual.integration;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.endpoint.dto.OwnerDto;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.web.server.LocalServerPort;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
public class OwnerEndpointTest {
|
||||||
|
@Value("${spring.upload.path}")
|
||||||
|
private String FILE_BASE_PATH;
|
||||||
|
private static final RestTemplate REST_TEMPLATE = new RestTemplate();
|
||||||
|
private static final String BASE_URL = "http://localhost:";
|
||||||
|
private static final String OWNER_URL = "/owners";
|
||||||
|
|
||||||
|
@LocalServerPort
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Adding a new owner with the correct parameters will return HTTP 201 and the new OwnerDto")
|
||||||
|
public void addingNewOwner_correctParameters_shouldReturnStatus201AndOwner() {
|
||||||
|
OwnerDto newOwner = new OwnerDto("Chad");
|
||||||
|
|
||||||
|
HttpEntity<OwnerDto> request = new HttpEntity<>(newOwner);
|
||||||
|
ResponseEntity<OwnerDto> response = REST_TEMPLATE
|
||||||
|
.exchange(BASE_URL + port + OWNER_URL, HttpMethod.POST, request, OwnerDto.class);
|
||||||
|
|
||||||
|
// Compare everything except ids and timestamps
|
||||||
|
assertEquals(response.getStatusCode(), HttpStatus.CREATED);
|
||||||
|
assertEquals(newOwner.getName(), response.getBody().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,13 @@ package at.ac.tuwien.sepm.assignment.individual.unit.persistence;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
|
||||||
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
|
||||||
public abstract class OwnerDaoTestBase {
|
public abstract class OwnerDaoTestBase {
|
||||||
|
|
||||||
@ -17,7 +19,21 @@ public abstract class OwnerDaoTestBase {
|
|||||||
@DisplayName("Finding owner by non-existing ID should throw NotFoundException")
|
@DisplayName("Finding owner by non-existing ID should throw NotFoundException")
|
||||||
public void findingOwnerById_nonExisting_shouldThrowNotFoundException() {
|
public void findingOwnerById_nonExisting_shouldThrowNotFoundException() {
|
||||||
assertThrows(NotFoundException.class,
|
assertThrows(NotFoundException.class,
|
||||||
() -> ownerDao.findOneById(1L));
|
() -> ownerDao.findOneById(0L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Adding a new owner with the correct parameters should return the owner")
|
||||||
|
public void addingNewOwner_correctParameters_shouldReturnOwner() {
|
||||||
|
Owner newOwner = new Owner("Chad");
|
||||||
|
Owner savedOwner = ownerDao.addOwner(newOwner);
|
||||||
|
assertEquals(newOwner, savedOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Adding a new horse with the incorrect parameters should throw DataAccessException")
|
||||||
|
public void addingNewOwner_incorrectParameters_shouldThrowDataAccess() {
|
||||||
|
Owner newOwner = new Owner("");
|
||||||
|
assertThrows(DataAccessException.class, () -> ownerDao.addOwner(newOwner));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package at.ac.tuwien.sepm.assignment.individual.unit.service;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.service.OwnerService;
|
||||||
|
import at.ac.tuwien.sepm.assignment.individual.util.ValidationException;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
public class OwnerServiceTest {
|
||||||
|
@Autowired
|
||||||
|
OwnerService ownerService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Adding a new owner with the correct parameters will return the new owner")
|
||||||
|
public void addingNewOwner_correctParameters_shouldReturnOwner() {
|
||||||
|
Owner newOwner = new Owner("Chad");
|
||||||
|
Owner savedOwner = ownerService.addOwner(newOwner);
|
||||||
|
assertEquals(newOwner, savedOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Adding a new owner with the incorrect parameters will throw a ValidationException")
|
||||||
|
public void addingNewOwner_incorrectParameters_shouldThrowValidation() {
|
||||||
|
Owner newOwner = new Owner("");
|
||||||
|
assertThrows(ValidationException.class, () -> ownerService.addOwner(newOwner));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user