diff --git a/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java b/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java index ade3ff4ff..4ce5a4255 100644 --- a/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java +++ b/src/main/java/io/spring/api/exception/CustomizeExceptionHandler.java @@ -21,6 +21,10 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +/** + * Global exception handler for REST API controllers. + */ + @RestControllerAdvice public class CustomizeExceptionHandler extends ResponseEntityExceptionHandler { @@ -59,6 +63,18 @@ public ResponseEntity handleInvalidAuthentication( }); } + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFound( + ResourceNotFoundException e, WebRequest request) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body( + new HashMap() { + { + put("message", "Resource not found"); + } + }); + } + @Override protected ResponseEntity handleMethodArgumentNotValid( MethodArgumentNotValidException e, diff --git a/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java b/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java index bf4768b3b..0919389f8 100644 --- a/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java +++ b/src/main/java/io/spring/graphql/exception/GraphQLCustomizeExceptionHandler.java @@ -9,6 +9,7 @@ import graphql.execution.DataFetcherExceptionHandlerResult; import io.spring.api.exception.FieldErrorResource; import io.spring.api.exception.InvalidAuthenticationException; +import io.spring.api.exception.ResourceNotFoundException; import io.spring.graphql.types.Error; import io.spring.graphql.types.ErrorItem; import java.util.ArrayList; @@ -38,6 +39,14 @@ public DataFetcherExceptionHandlerResult onException( .path(handlerParameters.getPath()) .build(); return DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build(); + } else if (handlerParameters.getException() instanceof ResourceNotFoundException) { + GraphQLError graphqlError = + TypedGraphQLError.newBuilder() + .errorType(ErrorType.NOT_FOUND) + .message("Resource not found") + .path(handlerParameters.getPath()) + .build(); + return DataFetcherExceptionHandlerResult.newResult().error(graphqlError).build(); } else if (handlerParameters.getException() instanceof ConstraintViolationException) { List errors = new ArrayList<>(); for (ConstraintViolation violation : diff --git a/src/test/java/io/spring/api/ProfileApiTest.java b/src/test/java/io/spring/api/ProfileApiTest.java index f32091ecd..09985970f 100644 --- a/src/test/java/io/spring/api/ProfileApiTest.java +++ b/src/test/java/io/spring/api/ProfileApiTest.java @@ -8,6 +8,7 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc; import io.spring.JacksonCustomizations; +import io.spring.api.exception.CustomizeExceptionHandler; import io.spring.api.security.WebSecurityConfig; import io.spring.application.ProfileQueryService; import io.spring.application.data.ProfileData; @@ -23,7 +24,7 @@ import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(ProfileApi.class) -@Import({WebSecurityConfig.class, JacksonCustomizations.class}) +@Import({WebSecurityConfig.class, JacksonCustomizations.class, CustomizeExceptionHandler.class}) public class ProfileApiTest extends TestWithCurrentUser { private User anotherUser; @@ -93,4 +94,44 @@ public void should_unfollow_user_success() throws Exception { verify(userRepository).removeRelation(eq(followRelation)); } + + @Test + public void should_get_404_when_follow_nonexistent_user() throws Exception { + when(userRepository.findByUsername(eq("nonexistent"))) + .thenReturn(Optional.empty()); + given() + .header("Authorization", "Token " + token) + .when() + .post("/profiles/{username}/follow", "nonexistent") + .prettyPeek() + .then() + .statusCode(404) + .body("message", equalTo("Resource not found")); + } + + @Test + public void should_get_404_when_unfollow_nonexistent_user() throws Exception { + when(userRepository.findByUsername(eq("nonexistent"))) + .thenReturn(Optional.empty()); + given() + .header("Authorization", "Token " + token) + .when() + .delete("/profiles/{username}/follow", "nonexistent") + .prettyPeek() + .then() + .statusCode(404) + .body("message", equalTo("Resource not found")); + } + + @Test + public void should_get_404_when_get_nonexistent_profile() throws Exception { + when(profileQueryService.findByUsername(eq("nonexistent"), eq(null))) + .thenReturn(Optional.empty()); + RestAssuredMockMvc.when() + .get("/profiles/{username}", "nonexistent") + .prettyPeek() + .then() + .statusCode(404) + .body("message", equalTo("Resource not found")); + } }