Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: issue130 Return a 404 error while adding a pet to an unexisting owner #138

Merged
merged 3 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -33,53 +34,76 @@
import static org.springframework.http.HttpStatus.BAD_REQUEST;

/**
* Global Exception handler for REST controllers.
* <p>
* This class handles exceptions thrown by REST controllers and returns
* appropriate HTTP responses to the client.
*
* @author Vitaliy Fedoriv
* @author Alexander Dudkin
*/

@ControllerAdvice
public class ExceptionControllerAdvice {

@ExceptionHandler(Exception.class)
public ResponseEntity<String> exception(Exception e) {
ObjectMapper mapper = new ObjectMapper();
ErrorInfo errorInfo = new ErrorInfo(e);
String respJSONstring = "{}";
try {
respJSONstring = mapper.writeValueAsString(errorInfo);
} catch (JsonProcessingException e1) {
e1.printStackTrace();
/**
* Record for storing error information.
* <p>
* This record encapsulates the class name and message of the exception.
*
* @param className The name of the exception class
* @param exMessage The message of the exception
*/
private record ErrorInfo(String className, String exMessage) {
thisdudkin marked this conversation as resolved.
Show resolved Hide resolved
public ErrorInfo(Exception ex) {
this(ex.getClass().getName(), ex.getLocalizedMessage());
}
return ResponseEntity.badRequest().body(respJSONstring);
}

/**
* Handles all general exceptions by returning a 500 Internal Server Error status with error details.
*
* @param e The exception to be handled
* @return A {@link ResponseEntity} containing the error information and a 500 Internal Server Error status
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorInfo> handleGeneralException(Exception e) {
ErrorInfo info = new ErrorInfo(e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(info);
}

/**
* Handles {@link DataIntegrityViolationException} which typically indicates database constraint violations.
* This method returns a 404 Not Found status if an entity does not exist.
*
* @param ex The {@link DataIntegrityViolationException} to be handled
* @return A {@link ResponseEntity} containing the error information and a 404 Not Found status
*/
@ExceptionHandler(DataIntegrityViolationException.class)
arey marked this conversation as resolved.
Show resolved Hide resolved
@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ResponseBody
public ResponseEntity<ErrorInfo> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
ErrorInfo errorInfo = new ErrorInfo(ex);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorInfo);
}

/**
* Handles exception thrown by Bean Validation on controller methods parameters
*
* @param ex The thrown exception
* @param request the current web request
*
* @return an empty response entity
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(code = BAD_REQUEST)
@ResponseStatus(BAD_REQUEST)
@ResponseBody
public ResponseEntity<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
public ResponseEntity<ErrorInfo> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingErrorsResponse errors = new BindingErrorsResponse();
BindingResult bindingResult = ex.getBindingResult();
HttpHeaders headers = new HttpHeaders();
if (bindingResult.hasErrors()) {
errors.addAllErrors(bindingResult);
headers.add("errors", errors.toJSON());
return ResponseEntity.badRequest().body(new ErrorInfo("MethodArgumentNotValidException", "Validation failed"));
}
return new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST);
return ResponseEntity.badRequest().build();
}

private class ErrorInfo {
public final String className;
public final String exMessage;

public ErrorInfo(Exception ex) {
this.className = ex.getClass().getName();
this.exMessage = ex.getLocalizedMessage();
}
}
}
12 changes: 6 additions & 6 deletions src/main/resources/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ paths:
required: true
responses:
201:
description: The pet owner was sucessfully added.
description: The pet owner was successfully added.
content:
application/json:
schema:
Expand Down Expand Up @@ -314,7 +314,7 @@ paths:
required: true
responses:
201:
description: The pet was sucessfully added.
description: The pet was successfully added.
content:
application/json:
schema:
Expand All @@ -326,7 +326,7 @@ paths:
schema:
$ref: '#/components/schemas/RestError'
404:
description: Pet not found.
description: Pet or Owner not found.
content:
application/json:
schema:
Expand Down Expand Up @@ -489,7 +489,7 @@ paths:
required: true
responses:
201:
description: The vet visit was sucessfully added.
description: The vet visit was successfully added.
content:
application/json:
schema:
Expand Down Expand Up @@ -1849,7 +1849,7 @@ components:
readOnly: true
timestamp:
title: Timestamp
description: The time the error occured.
description: The time the error occurred.
type: string
format: date-time
example: '2019-08-21T21:41:46.158+0000'
Expand Down Expand Up @@ -1886,7 +1886,7 @@ components:
properties:
message:
title: Message
description: The valiation message.
description: The validation message.
type: string
example: "[Path '/lastName'] Instance type (null) does not match any allowed primitive type (allowed: [\"string\"])"
readOnly: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ void testAddPetError() throws Exception {
String newPetAsJSON = mapper.writeValueAsString(newPet);
given(this.clinicService.findPetById(999)).willReturn(null);
this.mockMvc.perform(post("/api/pets")
.content(new String()).accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE))
// set empty JSON to force 400 error
.content("{}").accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isBadRequest());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void testCreateUserSuccess() throws Exception {
@WithMockUser(roles = "ADMIN")
void testCreateUserError() throws Exception {
User user = new User();
user.setUsername("username");
user.setUsername(""); // set empty username to force 400 error
user.setPassword("password");
user.setEnabled(true);
ObjectMapper mapper = new ObjectMapper();
Expand Down
Loading