jcrshankar
jcrshankar

Reputation: 1196

how to get custom error code through swagger annotation

*`I have below schema definition to represent commission amount in my openapi contract.`*


"properties": {
        "Amount": {
          "type": "number",
          "description": "The amount of tnx",
          "pattern" : "^-?[0-9]*(\\.([0-9]{1,2}))?$",
          "format": "big-decimal",
          "minimum": 0.01,
          "maximum": 49999.99,
          "exclusiveMinimum": false,
          "exclusiveMaximum": false,
          "example" : "9999.99"
        },

generated code:

@NotNull @Valid @DecimalMin("0.01") @DecimalMax("49999.99") 
  @Schema(name = "amount", example = "9999.99", description = "The amount of tnx", required = true)
  public BigDecimal getAmount() {
    return amount;
  }

when i gave above 50000 or below 0.01 its given the right validation message through post man

{
    "errors": [
        {
            "code": "DecimalMax",
            "message": "must be less than or equal to 49999.99",
            "field": "Amount"
        }
    ]
}


{
    "errors": [
        {
            "code": "DecimalMin",
            "message": "must be greater than or equal to 0.01",
            "field": "Amount"
        }
    ]
}

but i want override the code with some some number to represent the error code like 100,101 etc

{
    "errors": [
        {
            "code": "100",
            "message": "must be less than or equal to 49999.99",
            "field": "Amount"
        }
    ]
}

{
    "errors": [
        {
            "code": "101",
            "message": "must be greater than or equal to 0.01",
            "field": "Amount"
        }
    ]
}

can i specify any annotation on swagger to achieve this

Upvotes: 0

Views: 2289

Answers (1)

tbatch
tbatch

Reputation: 1849

By Default, when a field fails validation, Spring will throw a MethodArgumentNotValidException. This is managed internally by Springs spring-boot-starter-validation. You can override this exception handling using @RestControllerAdvice or @ControllerAdvice.

First, create a basic model for your response. Here is an extremely simple one.

@Setter
@Getter
public class RestException {
  String code;
  String message;
}

Then, create your controller advice class.

@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

  @Override
  protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

    RestException exception = new RestException();
    exception.setCode(HttpStatus.BAD_REQUEST.toString());
    var message = Optional.ofNullable(ex).map(MethodArgumentNotValidException::getBindingResult).map(BindingResult::getFieldError).orElse(null);

    exception.setMessage(Objects.isNull(message) ? "unidentified error" : message.getField() + " " + message.getDefaultMessage());

    return new ResponseEntity<>(exception, HttpStatus.BAD_REQUEST);
  }
}

this very simple example will return a response of

{
  "code": "400 BAD_REQUEST",
  "message": "amount must be greater than or equal to 0"
}

Note

You are free to set the code returned to the user as whatever you want (aka, exception.setCode("99999 MY_STATUS_CODE"). However, this will have no meaning to the user, as it won't match the headers sent by the controller as part of the ResponseEntity. I recommend sticking with defined HttpStatus types as the code you display back to your users.

Also, unless you are specifically trying to get a BigDecimal as your type, setting the format of the number to float or double will result in the expected dataType. Otherwise, declaring big-decimal isn't necessary, since that is the default for a number with no format defined.

Likewise, the defaults for exclusiveMinimum and exclusiveMaximum is false by default, so there is no need to include them in your schema.

Finally, I recommend adjusting your schema to include to response description. Something along the lines of this

responses:
  "200":
    description: OK
  "5XX":
    description: Unknown error has occurred
  "400":
    description: A required parameter is missing or an invalid datatype or value was provided for property.  
      Check the error message to check the invalid information, adjust the provided schema, and try again.

That should cover all of your bases. Feel free to expand the RestException and RestExceptionHandler classes. As I said, these are basic examples. You can make them much more robust (i.e. multiple returns based upon the field or error message).

Upvotes: 2

Related Questions