Added custom exception handlers
This commit is contained in:
parent
813b38aed1
commit
0757c02db0
@ -14,6 +14,14 @@ import java.util.HashMap;
|
||||
|
||||
@ControllerAdvice
|
||||
public class CustomExceptionsHandler {
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(GenericErrorException.class)
|
||||
public ResponseEntity<String> genericErrorException(GenericErrorException ex) {
|
||||
var error = new JsonEmitter<>(ex.getMessage()).emitJsonKey(ex.getKey());
|
||||
|
||||
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.ceticamarco.bits.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Bad Request")
|
||||
public class GenericErrorException extends RuntimeException {
|
||||
private final String key;
|
||||
|
||||
public GenericErrorException(String message, String key) {
|
||||
super(message);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public GenericErrorException() {
|
||||
super("Bad Request");
|
||||
this.key = "error";
|
||||
}
|
||||
|
||||
public String getKey() { return key; }
|
||||
}
|
@ -3,7 +3,7 @@ package com.ceticamarco.bits.exception;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value= HttpStatus.UNAUTHORIZED, reason="Unauthorized user")
|
||||
@ResponseStatus(value = HttpStatus.UNAUTHORIZED, reason = "Unauthorized User")
|
||||
public class UnauthorizedUserException extends RuntimeException {
|
||||
public UnauthorizedUserException(String message) {
|
||||
super(message);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.ceticamarco.bits.post;
|
||||
|
||||
import com.ceticamarco.bits.exception.GenericErrorException;
|
||||
import com.ceticamarco.bits.exception.UnauthorizedUserException;
|
||||
import com.ceticamarco.bits.json.JsonEmitter;
|
||||
import com.ceticamarco.bits.user.User;
|
||||
@ -28,14 +29,14 @@ public class PostController {
|
||||
public ResponseEntity<List<Post>> getPosts(@RequestBody User user) {
|
||||
// Check if email and password are specified
|
||||
if(user.getPassword() == null || user.getEmail() == null) {
|
||||
throw new UnauthorizedUserException("Specify both email and password");
|
||||
throw new GenericErrorException("Specify both email and password", "error");
|
||||
}
|
||||
|
||||
// Get post list
|
||||
var res = postService.getPosts(user);
|
||||
|
||||
// Check if user is authorized
|
||||
if(res.isLeft()) { // TODO: implement proper generic exception handler
|
||||
if(res.isLeft()) {
|
||||
throw new UnauthorizedUserException(res.getLeft().getMessage());
|
||||
}
|
||||
|
||||
@ -50,15 +51,13 @@ public class PostController {
|
||||
*/
|
||||
@GetMapping("/api/posts/{postId}")
|
||||
public ResponseEntity<String> getPostById(@PathVariable("postId") String postId) {
|
||||
var res = postService.getPostById(postId)
|
||||
.map(post -> new JsonEmitter<>(post).emitJsonKey())
|
||||
.swap()
|
||||
.map(error -> new JsonEmitter<>(error.getMessage()).emitJsonKey("error"))
|
||||
.swap();
|
||||
var res = postService.getPostById(postId);
|
||||
if(res.isLeft()) {
|
||||
throw new GenericErrorException(res.getLeft().getMessage(), "error");
|
||||
}
|
||||
|
||||
return res.isRight()
|
||||
? new ResponseEntity<>(res.get(), HttpStatus.OK)
|
||||
: new ResponseEntity<>(res.getLeft(), HttpStatus.BAD_REQUEST);
|
||||
var jsonOutput = new JsonEmitter<>(res.get()).emitJsonKey();
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,14 +71,14 @@ public class PostController {
|
||||
public ResponseEntity<List<Post>> getPostByTitle(@RequestBody Post req) {
|
||||
// Check if email and password are specified
|
||||
if(req.getUser() == null || req.getUser().getPassword() == null || req.getUser().getEmail() == null) {
|
||||
throw new UnauthorizedUserException("Specify both email and password");
|
||||
throw new GenericErrorException("Specify both email and password", "error");
|
||||
}
|
||||
|
||||
// Get post by title
|
||||
var res = postService.getPostByTitle(req);
|
||||
|
||||
// Check if user is authorized
|
||||
if(res.isLeft()) { // TODO: implement proper generic exception handler
|
||||
if(res.isLeft()) {
|
||||
throw new UnauthorizedUserException(res.getLeft().getMessage());
|
||||
}
|
||||
|
||||
@ -94,15 +93,13 @@ public class PostController {
|
||||
*/
|
||||
@PostMapping("/api/posts/new")
|
||||
public ResponseEntity<String> submitPost(@Valid @RequestBody Post post) {
|
||||
var res = postService.addNewPost(post)
|
||||
.map(postId -> new JsonEmitter<>(postId).emitJsonKey("post_id"))
|
||||
.swap()
|
||||
.map(error -> new JsonEmitter<>(error.getMessage()).emitJsonKey("error"))
|
||||
.swap();
|
||||
var res =postService.addNewPost(post);
|
||||
if(res.isLeft()) {
|
||||
throw new GenericErrorException(res.getLeft().getMessage(), "error");
|
||||
}
|
||||
|
||||
return res.isRight()
|
||||
? new ResponseEntity<>(res.get(), HttpStatus.OK)
|
||||
: new ResponseEntity<>(res.getLeft(), HttpStatus.BAD_REQUEST);
|
||||
var jsonOutput = new JsonEmitter<>(res.get()).emitJsonKey("post_id");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,15 +111,14 @@ public class PostController {
|
||||
*/
|
||||
@PutMapping("/api/posts/{postId}")
|
||||
public ResponseEntity<String> updatePost(@Valid @RequestBody Post post, @PathVariable("postId") String postId) {
|
||||
// Update post
|
||||
var res = postService.updatePost(post, postId);
|
||||
if(res.isPresent()) {
|
||||
throw new GenericErrorException(res.get().getMessage(), "error");
|
||||
}
|
||||
|
||||
return res.map(error -> {
|
||||
var jsonOutput = new JsonEmitter<>(res.get().getMessage()).emitJsonKey("error");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.BAD_REQUEST);
|
||||
}).orElseGet(() -> {
|
||||
var jsonOutput = new JsonEmitter<String>("OK").emitJsonKey("status");
|
||||
var jsonOutput = new JsonEmitter<>("OK").emitJsonKey("status");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,12 +138,11 @@ public class PostController {
|
||||
|
||||
// Delete the post
|
||||
var res = postService.deletePost(user, postId);
|
||||
return res.map(error -> {
|
||||
var jsonOutput = new JsonEmitter<>(error.getMessage()).emitJsonKey("error");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.BAD_REQUEST);
|
||||
}).orElseGet(() -> {
|
||||
if(res.isPresent()) {
|
||||
throw new GenericErrorException(res.get().getMessage(), "error");
|
||||
}
|
||||
|
||||
var jsonOutput = new JsonEmitter<>("OK").emitJsonKey("status");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.ceticamarco.bits.user;
|
||||
|
||||
import com.ceticamarco.bits.exception.GenericErrorException;
|
||||
import com.ceticamarco.bits.exception.UnauthorizedUserException;
|
||||
import com.ceticamarco.bits.json.JsonEmitter;
|
||||
import jakarta.validation.Valid;
|
||||
@ -29,14 +30,14 @@ public class UserController {
|
||||
public ResponseEntity<List<User>> getUsers(@RequestBody User user) {
|
||||
// Check if email and password are specified
|
||||
if(user.getPassword() == null || user.getEmail() == null) {
|
||||
throw new UnauthorizedUserException("Specify both email and password");
|
||||
throw new GenericErrorException("Specify both email and password", "error");
|
||||
}
|
||||
|
||||
// Get post list
|
||||
var res = userService.getUsers(user);
|
||||
|
||||
// Check if user is authorized
|
||||
if(res.isLeft()) { // TODO: implement proper generic exception handler
|
||||
if(res.isLeft()) {
|
||||
throw new UnauthorizedUserException(res.getLeft().getMessage());
|
||||
}
|
||||
|
||||
@ -51,15 +52,13 @@ public class UserController {
|
||||
*/
|
||||
@PostMapping("/api/users/new")
|
||||
public ResponseEntity<String> submitUser(@Valid @RequestBody User user) {
|
||||
var res = userService.addNewUser(user)
|
||||
.map(userId -> new JsonEmitter<>(userId).emitJsonKey("user_id"))
|
||||
.swap()
|
||||
.map(error -> new JsonEmitter<>(error.getMessage()).emitJsonKey("error"))
|
||||
.swap();
|
||||
var res = userService.addNewUser(user);
|
||||
if(res.isLeft()) {
|
||||
throw new GenericErrorException(res.getLeft().getMessage(), "error");
|
||||
}
|
||||
|
||||
return res.isRight()
|
||||
? new ResponseEntity<>(res.get(), HttpStatus.OK)
|
||||
: new ResponseEntity<>(res.getLeft(), HttpStatus.BAD_REQUEST);
|
||||
var jsonOutput = new JsonEmitter<>(res.get()).emitJsonKey("user_id");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,17 +71,15 @@ public class UserController {
|
||||
public ResponseEntity<String> deleteUser(@RequestBody User user) {
|
||||
// Check if email and password are specified
|
||||
if(user.getPassword() == null || user.getEmail() == null) {
|
||||
var res = new JsonEmitter<>("Specify both email and password").emitJsonKey("error");
|
||||
return new ResponseEntity<>(res, HttpStatus.BAD_REQUEST);
|
||||
throw new GenericErrorException("Specify both email and password", "error");
|
||||
}
|
||||
// Delete the user
|
||||
var res = userService.deleteUser(user);
|
||||
return res.map(error -> {
|
||||
var jsonOutput = new JsonEmitter<>(error.getMessage()).emitJsonKey("error");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.BAD_REQUEST);
|
||||
}).orElseGet(() -> {
|
||||
if(res.isPresent()) {
|
||||
throw new GenericErrorException(res.get().getMessage(), "error");
|
||||
}
|
||||
|
||||
var jsonOutput = new JsonEmitter<>("OK").emitJsonKey("status");
|
||||
return new ResponseEntity<>(jsonOutput, HttpStatus.OK);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -1,14 +1,14 @@
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.hibernate.ddl-auto=create-drop
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
|
||||
spring.jpa.properties.hibernate.format_sql=true
|
||||
|
||||
# Adjust these values in production
|
||||
#server.port=3000
|
||||
#spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/bit
|
||||
#spring.datasource.username=postgres
|
||||
#spring.datasource.password=toor
|
||||
#spring.security.user.name=admin
|
||||
#spring.security.user.password=admin
|
||||
server.port=3000
|
||||
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/bit
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=toor
|
||||
spring.security.user.name=admin
|
||||
spring.security.user.password=admin
|
||||
|
||||
# For unit tests only
|
||||
#spring.datasource.url=jdbc:h2:mem:testdb
|
||||
|
@ -41,14 +41,18 @@ public class PostControllerTests {
|
||||
post.setTitle("test");
|
||||
post.setContent("This is a test");
|
||||
|
||||
when(postService.getPosts()).thenReturn(List.of(post));
|
||||
var user = new User();
|
||||
user.setEmail("john@example.com");
|
||||
user.setPassword("qwerty");
|
||||
|
||||
when(postService.getPosts(any(User.class))).thenReturn(Either.right(List.of(post)));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/api/posts")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(post)))
|
||||
.content(objectMapper.writeValueAsString(user)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
Mockito.verify(postService, Mockito.times(1)).getPosts();
|
||||
Mockito.verify(postService, Mockito.times(1)).getPosts(any(User.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -71,18 +75,22 @@ public class PostControllerTests {
|
||||
@Test
|
||||
public void getPostByTitle() throws Exception {
|
||||
var post = new Post();
|
||||
var user = new User();
|
||||
user.setEmail("john@example.com");
|
||||
user.setPassword("qwerty");
|
||||
post.setId("abc123");
|
||||
post.setTitle("test");
|
||||
post.setContent("This is a test");
|
||||
post.setUser(user);
|
||||
|
||||
when(postService.getPostByTitle(anyString())).thenReturn(List.of(post));
|
||||
when(postService.getPostByTitle(any(Post.class))).thenReturn(Either.right(List.of(post)));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/api/posts/bytitle")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(post)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
Mockito.verify(postService, Mockito.times(1)).getPostByTitle(anyString());
|
||||
Mockito.verify(postService, Mockito.times(1)).getPostByTitle(any(Post.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -15,6 +15,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@ -31,6 +32,23 @@ class UserControllerTest {
|
||||
@MockBean
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
public void getUsers() throws Exception {
|
||||
var user = new User();
|
||||
user.setUsername("john");
|
||||
user.setEmail("john@example.com");
|
||||
user.setPassword("qwerty");
|
||||
|
||||
when(userService.getUsers(any(User.class))).thenReturn(Either.right(List.of(user)));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(user)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
Mockito.verify(userService, Mockito.times(1)).getUsers(any(User.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addNewUser() throws Exception {
|
||||
var user = new User();
|
||||
|
Loading…
Reference in New Issue
Block a user