To define endpoints in our Ratpack application we can use optional path tokens. This means that a part of the request can have a value or not, but we can a have single path definition that will match. Normally we define a variable path token with a colon (:) followed by a variable name. To make this token optional we follow it with a question mark (?). This tells Ratpack that the token can have a value or not. In our handler we now need to take into account that the path token is optional as well.

Let's write a sample Ratpack application with a path definition containing an optional token. We define a path binding for profiles/:username?. The path token username is available in our handler if the value is set, but also a request for profiles will match for this binding. Then the value for username is not set.

// File: src/ratpack/Ratpack.groovy
import static ratpack.groovy.Groovy.ratpack

ratpack {

    handlers {

        // Specify the optional path token username.
        // This path definition will match for
        // request paths like profiles/mrhaki and
        // profiles (without slash and username value).
        path('profiles/:username?') {

            // Simply render the value of the username
            // path token if set, otherwise return "all"
            render pathTokens.getOrDefault('username', 'all')
        }

    }
}

We write the following test to check the different responses we get when we provide values for the optional token or leave out a value:

// File: src/test/groovy/com/mrhaki/ratpack/pathbinding/OptionalPathBindingSpec.groovy
package com.mrhaki.ratpack.pathbinding

import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll

class OptionalPathBindingSpec extends Specification {

    @AutoCleanup
    @Shared
    GroovyRatpackMainApplicationUnderTest app =
            new GroovyRatpackMainApplicationUnderTest()

    @Unroll('path #path should return "#expectedResponse"')
    def "check response for request with and without optional token"() {
        when:
        def response = app.httpClient.get(path)

        then:
        response.body.text == expectedResponse

        where:
        path                  || expectedResponse
        '/profiles/mrhaki'    || 'mrhaki'
        '/profiles/hubert'    || 'hubert'
        '/profiles'           || 'all'
        '/profiles/'          || ''
        '/profiles/mrhaki/42' || 'Client error 404'
    }

}

Written with Ratpack 1.1.1.

Original article

shadow-left