Monday 7 December 2015

Adding Validation to a REST API with Spring MVC

We want to use the JSR-303 backed validation with Spring Framework, we have to add a JSR-303 provider to our classpath. Here we are using Hibernate Validator 4.2.0 which is the reference implementation of the Bean Validation API (JSR-303).

Step-1
Add below dependency.....

<!-- Form Validation using Annotations
        JSR 303 - Bean 
        -->  
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>

</dependency>

Step-2
Enable the validation
Add below entry inside the spring web application context file....


<!-- it enable rest annotation +Validation + Support JSON and XML Response if their lib are in the classpath -->

     <mvc:annotation-driven/>


Step-3
define resource bundle for error message

<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:message" />
<property name="defaultEncoding" value="UTF-8" />

</bean>

Step-4
message_en.properties

#application defined error messsages
id.required=Employee ID is required
name.required=Employee Name is required
role.required=Employee Role is required

negativeValue={0} can't be negative or zero

Step-5
Applying annotation for validation on bean class
public class LoginVO {
@Size(min=6,max=15)
@NotEmpty
private String phone;
private String token;

public String getPhone() {
return phone;
}

public void setPhone(String phone) {

}
}

Step-6
Applying annotation in restful web service.
@RequestMapping(value = LevelURIConstant.VALIDATE_LOGIN, method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody
UserMessage authUserByPhoneValidate(@Valid @RequestBody LoginVO phone) {
String pphone="";
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(phone.getPhone());
if(m.find()){
pphone=m.group();
}
if(LOG.isDebugEnabled()) 
LOG.debug("Executing the method findLevel.."+phone);
String result=iUserService.authUserByPhone(phone.getPhone());
UserMessage userMessage=new UserMessage();
if(!"fail".equals(result)){
userMessage.setStatus("success");
userMessage.setMessage("Login Successfully");
userMessage.setToken(phone.getPhone());
}else{
userMessage.setStatus("failed");
userMessage.setMessage("Login Failed");
   userMessage.setToken("unknown");
}
return userMessage;
}


Step-7
Define pojo for error message
public class QuizErrorInfo {
private String status;
private String code;
private String message;
private String ex;
private String moreInfo;
         public QuizErrorInfo(String status, String code, String message, String ex,
String moreInfo) {
this.status = status;
this.code = code;
this.message = message;
this.ex = ex;
this.moreInfo = moreInfo;
}
}



Step-8
Define global exception handler for handling error message
using spring annotation @ControllerAdvice since spring 3.2

@ControllerAdvice
public class GPSGlobalExceptionHandler { 

@ExceptionHandler(MethodArgumentNotValidException.class)
 @ResponseStatus(HttpStatus.BAD_REQUEST)
 @ResponseBody
 public QuizErrorInfo processValidationError(HttpServletRequest req,MethodArgumentNotValidException ex) {
   BindingResult result = ex.getBindingResult();
   List<FieldError> fieldErrors = result.getFieldErrors();
   String errors= processFieldErrors(fieldErrors);
   QuizErrorInfo errorInfo=new QuizErrorInfo(HttpStatus.BAD_REQUEST.toString(),"3000" , errors, ex.getClass().toString(), req.getRequestURL().toString());
   return errorInfo;
 }

private String processFieldErrors(List<FieldError> fieldErrors) {
StringBuilder builder=new StringBuilder();
        for (FieldError fieldError: fieldErrors) {
        builder.append(fieldError.getField()+" = "+fieldError.getDefaultMessage()+" , ");
        }
        return builder.toString();

    }

}

http://localhost:5050/app-name/android/v1/vlogin

Input for above rest web service
{"phone":"02","token":"9873003702"}

output :
{
  "status": "400",
  "code": "3000",
  "message": "phone = size must be between 6 and 15 , ",
  "ex": "class org.springframework.web.bind.MethodArgumentNotValidException",
  "moreInfo": "http://localhost:5050/com.gps.quiz/android/v1/vlogin"

}






No comments:

Post a Comment