Swagger Request Validator with Grails 3.2.x

Ever heard the phrase “Never Trust User Inputs”? This is one of the most important things a developer has to keep in mind while writing code. We have all been through the tedious task of validating request before starting to process it. If that’s not tedious enough, we also have to add test cases to verify that the validations indeed are working properly.

Wouldn’t it be great if all that extra work can be avoided just by using an open source Java library which does that for us!

Recently, we decided to use Swagger Request Validator that validates the Http request/response against an OpenAPI specification. The idea was to integrate this library with Grails framework. In this article, we will see how to achieve this without breaking a sweat.

I am assuming that you are already familiar with Grails filters and interceptors. So let’s start…

No surprise, the first step would be to add the library as a dependency to our application. Add compile “com.atlassian.oai:swagger-request-validator-springmvc:1.3.2″ to the dependencies section of your  build.gradle file.

Note: If you are using MongoDB with your app, you might need an extra dependency for a validator else your app may not boot. In that case add compile “org.hibernate:hibernate-validator:5.2.4.Final” to the dependencies block.

If you see the Swagger Request Validator Spring MVC docs, you will find, to use Swagger Request Validator, we need to register SwaggerValidationInterceptor and add SwaggerValidationFilter to our application. Registering a filter is quite easy in Grails. As the docs suggest, all we have to do is add it as a spring bean in resources.groovy file. However, for our use case, we will have to modify the filter registration order a bit. I will come to that shortly. Here is a code snippet of how I added and manipulated the filter in my application –

import com.atlassian.oai.validator.springmvc.SwaggerValidationFilter
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.core.Ordered

beans {
    swaggerValidationFilter(FilterRegistrationBean) {
        filter = bean(SwaggerValidationFilter)
        urlPatterns = ['/*']
        order = (Ordered.LOWEST_PRECEDENCE - 1)
    }
}

 

Next, we initialize SwaggerValidationInterceptor in our application.

import com.atlassian.oai.validator.springmvc.SwaggerValidationInterceptor
import org.apache.catalina.connector.RequestFacade
import org.grails.plugins.web.interceptors.GrailsInterceptorHandlerInterceptorAdapter
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse;

/**
 * This interceptor is to initialize SwaggerValidationInterceptor and 
 * call the preHandle method.
 * To make it work, we need to register SwaggerValidationFilter which has
 * been done in resources.groovy file.
 */
class RequestValidatorInterceptor extends GrailsInterceptorHandlerInterceptorAdapter {

    private final SwaggerValidationInterceptor swaggerValidationInterceptor

    RequestValidatorInterceptor(@Value("classpath:swagger-api.json") 
            final Resource swaggerApi) throws IOException {
        final EncodedResource swaggerResource = new EncodedResource(swaggerApi, "UTF-8");
        this.swaggerValidationInterceptor = 
                new SwaggerValidationInterceptor(swaggerResource)
    }

    @Override
        boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                Object handler) throws Exception {
        swaggerValidationInterceptor.preHandle(request, response, handler)
    }
 }

Coming back to the order of filter registration, let’s talk about the need to do that. If you see the preHandle method in SwaggerValidationInterceptor, there is check which verifies that the request object an instance of ResettableRequestServletWrapper class. If the check fails then validations will not be executed. The reason behind this is to read the request during and then reset the stream so that it can be read again at the controller end. So when the request object comes out of FilterChain, it is absolutely necessary that it is wrapped into ResettableRequestServletWrapper class. SwaggerValidationFilter does that for us and hence the order has been set close to lowest precedence. But the question is, why close to lowest precedence and why not absolutely low?

 

To answer this question, let’s understand how GrailsWebRequestFilter works. The GrailsWebRequest class stores the request object bound to the current request and the same is accessed at the controller end. This object is created when the request passes through GrailsWebRequestFilter. So, it is important that when the request passes through GrailsWebRequestFilter, it’s already wrapped in ResettableRequestServletWrapper else you won’t be able to able to retrieve data from the request object. Keeping all this in mind it can be deduced that we need to add GrailsWebRequestFilter after SwaggerValidationFilter in the FilterChain.

 

And how do we do that? Simple. Grails provides the flexibility to manipulate filter registration order by adding a few properties in the application.groovy file. Add the following code snippet to application.groovy file in order to change the position of GrailsWebRequestFilter in FilterChain –

beans {
    grailsWebRequestFilter {
        order = (Ordered.LOWEST_PRECEDENCE)
    }
 }

If you wish to add this in the application.yml file, change the structure accordingly.

Now the final step is to create a JSON file which defines the request and response structure for various paths. This file should be present in src/main/resources/ directory. Have a look at this sample file to do that.

For debugging purposes, you might want to configure your logback file. This article on configuring logback might be helpful.

 

Feel free to post your queries in the comments section below.

 

About CauseCode: We are a technology company specializing in Healthtech related Web and Mobile application development. We collaborate with passionate companies looking to change health and wellness tech for good. If you are a startup, enterprise or generally interested in digital health, we would love to hear from you! Let's connect at bootstrap@causecode.com

Leave a Reply

Your email address will not be published. Required fields are marked *

STAY UPDATED!

Do you want to get articles like these in your inbox?

Email *

Interested groups *
Healthtech
Business
Technical articles

Archives