Mike
Mike

Reputation: 8100

Validating Spring @PathVariable in Kotlin Controller

I'm attempting to validate a String @PathVariable inside a Kotlin Spring controller.

@RestController
@Validated
@RequestMapping("/kotlin/")
open class KStringController {

    @GetMapping(path = ["string/{username}"],
            produces = [APPLICATION_JSON_VALUE])
    @ResponseBody
    fun validateStringPathVariable(
            @Pattern(regexp = "[A-Za-z]+", message = "Username Pattern Validation Message")
            @Size(min = 2, max = 15, message = "Username Size Validation Message")
            @PathVariable("username") username: String?
    ): ResponseEntity<String>? {
        logger.info { String.format("validateStringPathVariable: Got Username [%s]", username) }
        System.out.printf("validateStringPathVariable: Username is [%s]%n", username)

        return ResponseEntity.ok("Username is valid")
    }
}

I have unit tests for it:

@ExtendWith(SpringExtension::class)
@WebMvcTest(KStringController::class)
@AutoConfigureMockMvc
class KStringGetControllerTest {
    @field:Autowired
    private lateinit var mvc: MockMvc

    @Test
    @Throws(Exception::class)
    fun validStringPathVariable() {
        val request: MockHttpServletRequestBuilder = givenARequestFor("/kotlin/string/mike")
        val actions: ResultActions = whenTheRequestIsMade(request)
        thenExpect(actions,
                MockMvcResultMatchers.status().isOk,
                MockMvcResultMatchers.content().bytes("Username is valid".toByteArray()))
    }

    @Test
    @Throws(Exception::class)
    fun shoutsWhenStringPathVariableIsTooShort() {
        val request = givenARequestFor("/kotlin/string/a")
        val actions = whenTheRequestIsMade(request)
        val response = """{
    "validationErrors": [
        {
            "fieldName": "validateStringPathVariable.username",
            "message": "Username Size Validation Message"
        }
    ]
}"""
        val content = MockMvcResultMatchers.content()
        thenExpect(actions,
                MockMvcResultMatchers.status().isBadRequest,
                content.contentType(MediaType.APPLICATION_JSON),
                content.json(response))
    }

    private fun givenARequestFor(url: String): MockHttpServletRequestBuilder {
        return MockMvcRequestBuilders.get(url)
                .characterEncoding("UTF-8")
    }

    @Throws(Exception::class)
    private fun whenTheRequestIsMade(request: MockHttpServletRequestBuilder): ResultActions {
        return mvc.perform(request)
    }

    @Throws(Exception::class)
    private fun thenExpect(resultActions: ResultActions, vararg matchers: ResultMatcher) {
        resultActions.andExpect(ResultMatcher.matchAll(*matchers))
    }

Currently the second test is failing; it's returning a 200 response code when I'm expecting a 400. Much much more code at https://github.com/Mavelous/spring-validation.

Upvotes: 0

Views: 1993

Answers (1)

Mike
Mike

Reputation: 8100

With help from others, I've managed to find a solution.

Quick answer: Change the function to open fun validateStringPathVariable, and the validations will start working.

Alternative answer: Use the org.jetbrains.kotlin.plugin.spring plugin in your build.gradle file.

I also created a blog post with a longer description: http://mavelo.us/2021/04/07/spring-validation-in-kotlin.html

Upvotes: 2

Related Questions