timo
timo

Reputation: 113

Different response models in spring

I am using maven codgen plugin to generate code for me. However, I would like to return a different model if an APIexception is caught. But it seems not working.

I would like to return e.getResponseBody(); whatever it is returned by external api. But the error model is not the same as List.

eg. using the simple pet example (and changing the 'default' response to '400'):

      responses:
        '200':
          description: pet response
          schema:
            type: array
            items:
              $ref: '#/definitions/pet'
        '400':
          description: unexpected error
          schema:
            $ref: '#/definitions/errorModel'

Generates the following interface:

@ApiOperation(value = "", notes = "Returns all pets from the system that the user has access to", response = Pet.class, responseContainer = "List", tags={  })
    @ApiResponses(value = { 
        @ApiResponse(code = 200, message = "pet response", response = Pet.class),
        @ApiResponse(code = 400, message = "unexpected error", response = errorModel.class) })
    @RequestMapping(value = "/pets",
        produces = { "application/json", "application/xml", "text/xml", "text/html" }, 
        consumes = { "application/json" },
        method = RequestMethod.GET)
    ResponseEntity<List<Pet>> findPets(@ApiParam(value = "tags to filter by") @RequestParam(value = "tags", required = false) List<String> tags,
        @ApiParam(value = "maximum number of results to return") @RequestParam(value = "limit", required = false) Integer limit);

The controller

 ResponseEntity<List<Pet>> findPets(@ApiParam(value = "tags to filter by") @RequestParam(value = "tags", required = false) List<String> tags,
        @ApiParam(value = "maximum number of results to return") @RequestParam(value = "limit", required = false) Integer limit){
   try{
     //call external api which throw a API exception if fail
   }
   catch(ApiException e){
   // I would like to return e.getResponseBody(); whatever it is returned by external api. 
  // But the error model is not the same as List<Pet>
}

}

Upvotes: 1

Views: 1020

Answers (1)

Stanislas Klukowski
Stanislas Klukowski

Reputation: 327

Spring offers you a better way than catching your ApiException directly in the controller. You should document yourself on exception handling in REST apis (consider reading https://www.baeldung.com/exception-handling-for-rest-with-spring)

Depending on your version of spring, you could use @ControllerAdvice annotation which I think is the simplest way to do that.

Remove the try/catch from your controller :

ResponseEntity<List<Pet>> findPets(@ApiParam(value = "tags to filter by") @RequestParam(value = "tags", required = false) List<String> tags,
        @ApiParam(value = "maximum number of results to return") @RequestParam(value = "limit", required = false) Integer limit) 
throws ApiException
{
   
   //call external api which throw a API exception if fail
   
}

Create a class annotated with @ControllerAdvice

@ControllerAdvice
public class APIExceptionHandler 
  extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value 
      = ApiException.class)
    protected ResponseEntity<MyExceptionResponseDto> handleException(
      ApiException ex, WebRequest request) {
        MyExceptionResponseDto apiError = ... //TODO
        return new ResponseEntity<>(apiError, HttpStatus.INTERNAL_SERVER_ERROR)
    }
}

NB : MyExceptionResponseDto is the DTO which will represent your error response

This also allows you to choose a specific HTTP error code which is important for the client when it handles error (not just based on an attribute in your json)

Upvotes: 1

Related Questions