I'm trying to use Grails interceptors to match specific uri having specific HTTP methods. The method argument of the match method is however ignored, despite the fact that I upgraded my Grails version from 3.1.1 to 3.1.16, where that issue should be fixed.
An simplified version of my code would be:
@GrailsCompileStatic
class MyInterceptor {
int order = HIGHEST_PRECEDENCE
MyInterceptor () {
match(uri: '/api/domain/*', method: 'PUT')
match(uri: '/api/domain/*', method: 'DELETE')
match(uri: '/api/domain/*', method: 'POST')
}
}
With the following interceptor test:
@TestFor(MyInterceptor)
class MyInterceptorSpec extends Specification {
@Unroll
def "it matches '#method #uri'"() {
when: "A request matches the interceptor"
withRequest(uri: uri, method: method)
then:"The interceptor does match"
interceptor.doesMatch()
where:
uri | method
'/api/domain/1' | 'PUT'
'/api/domain/1' | 'POST'
'/api/domain/1' | 'DELETE'
}
@Unroll
def "it does not match '#method #uri'"() {
when:
withRequest(uri: uri, method: method)
then:
!interceptor.doesMatch()
where:
uri | method
'/api/domain' | 'GET'
'/api/domain/1' | 'GET' // failing test
}
}
How can I ensure that the interceptor match uris only for given HTTP methods?
It is not possible by default in Grails.
Looking at the code of the UrlMappingMatcher we can see that when we define a matching rule with an uri, the method part is ignored:
You can however create a subclass of UrlMappingMatcher that takes into account the method even when an uri is defined, and use it instead of the regular one in your Interceptor: