Tuesday, May 7, 2013

Testing REST requests to a Spring MVC backend

Download WizTools RestClient and start it

You can download the WizTools rest client over following site: Google Project.

I have just downloaded the jar.

To start the client I executed the following command:

java -jar restclient-ui-3.1-jar-with-dependencies.jar

Setting loglevel in logback.xml

To actually see what Spring is doing it is necessary to set the web.servlet.mvc log level to TRACE. Only then Spring is actually revealing what is happening under the hood with the json jackson converter and also displays what went wrong if the RequestBody couldn't be processed.

<configuration>
  <contextListener 
   class="ch.qos.logback.classic.jul.LevelChangePropagator">
    <resetJUL>true</resetJUL>
  </contextListener>

  <!-- To enable JMX Management -->
  <jmxConfigurator/>

  <appender name="STDOUT" 
   class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
  </appender>

  <logger name="com.eerra.cardkeeper" level="INFO" />
  <logger name="org.springframework" level="TRACE" />
  <logger name="org.springframework.beans" level="WARN" />
  <logger 
   name="org.springframework.web.servlet.mvc" 
   level="TRACE" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

Pitfall 400 Bad Request

Without setting TRACE on web.servlet.mvc it will be impossible to debug errors on the interface. For example I have single-quoted my attributes and values which just resulted in a 400 Bad Request:

{
  'email': 'test@test.com',
  'firstName': 'Testfirst',
  'lastName': 'Testlast'
}
After enabling TRACE I have seen following message in the Spring log:
org.springframework.http.converter.
HttpMessageNotReadableException: 
Could not read JSON: Unexpected character (''' (code 39)): 
was expecting double-quote to start field name
at [Source: org.eclipse.jetty.server.HttpInput@69663655; 
line: 2, column: 3]; 
nested exception is org.codehaus.jackson.JsonParseException: 
Unexpected character (''' (code 39)): 
was expecting double-quote to start field name
at [Source: org.eclipse.jetty.server.HttpInput@69663655; 
line: 2, column: 3]
After double-quoting the attributes and values it worked:
{
  "email": "test@test.com",
  "firstName": "Testfirst",
  "lastName": "Testlast"
}

5 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. In Spring you can use a GlobalErrorController that will return the error as json or xml.

    @ControllerAdvice
    public class GlobalErrorController {
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ExceptionResponse handleException(MethodArgumentNotValidException ex) {
    List fieldErrors = ex.getBindingResult().getFieldErrors();
    List globalErrors = ex.getBindingResult().getGlobalErrors();
    List errors = new ArrayList(fieldErrors.size() + globalErrors.size());
    String error;
    for (FieldError fieldError : fieldErrors) {
    error = fieldError.getDefaultMessage();
    errors.add(error);
    }
    for (ObjectError objectError : globalErrors) {
    error = objectError.getDefaultMessage();
    errors.add(error);
    }
    ExceptionResponse response = new ExceptionResponse();
    response.setStatus(HttpStatus.BAD_REQUEST.value()); // 400
    response.setMessage(HttpStatus.BAD_REQUEST.getReasonPhrase());
    response.setDeveloperMessage(ex.getMessage());
    response.setErrors(errors);
    return response;
    }
    }

    ReplyDelete
  3. Thank you for your reply!
    I've tried this but I can't get any message.
    Code in my global error controller:
    @ExceptionHandler(JsonParseException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public String handleJsonParseException(JsonParseException ex) {
    String returnMessage = "JSON syntax error";
    if (!StringUtils.isEmpty(ex.getMessage())) {
    returnMessage = ex.getMessage();
    }
    return returnMessage;
    }
    And in my endpoint I throw JsonParseException.

    ReplyDelete
    Replies
    1. I found that in spring framework this kind of exceptions have been resolved in DispatcherServlet class. Maybe that's why I can't catch JsonParseException in my endpoint.

      Delete
    2. Read about @ControllerAdvice in the Spring docs. That's what I did to understand how it works.

      Delete