Hello <#C5AL3AKUY|http4k> ! I have a question rel...
# http4k
b
Hello #http4k ! I have a question related to
http4k-contract
From http4k's documentation https://www.http4k.org/guide/reference/contracts/, the following example is shown
Copy code
// this route has a dynamic path segment
fun greetRoute(): ContractRoute {

    // these lenses define the dynamic parts of the request that will be used in processing
    val ageQuery = <http://Query.int|Query.int>().required("age")
    val stringBody = Body.string(TEXT_PLAIN).toLens()

    // this specifies the route contract, with the desired contract of path, headers, queries and body parameters.
    val spec = "/greet" / Path.of("name") meta {
        summary = "tells the user hello!"
        queries += ageQuery
        receiving(stringBody)
    } bindContract GET

    // the this function will dynamically supply a new HttpHandler for each call. The number of parameters
    // matches the number of dynamic sections in the path (1)
    fun greet(nameFromPath: String): HttpHandler = { request: Request ->
        val age = ageQuery(request)
        val sentMessage = stringBody(request)

        Response(OK).with(stringBody of "hello $nameFromPath you are $age. You sent $sentMessage")
    }

    return spec to ::greet
}
The above example is fine for path with Path Lens as the last 'path component', however, for path that has string as the last 'path component', I must include a extra parameter for function
greet
, e.g.
Copy code
// this route has a dynamic path segment
fun greetRoute(): ContractRoute {

    // these lenses define the dynamic parts of the request that will be used in processing
    val ageQuery = <http://Query.int|Query.int>().required("age")
    val stringBody = Body.string(TEXT_PLAIN).toLens()

    // this specifies the route contract, with the desired contract of path, headers, queries and body parameters.
    val spec = "/greet" / Path.of("name") / "foo" meta {
        summary = "tells the user hello!"
        queries += ageQuery
        receiving(stringBody)
    } bindContract GET

    // the this function will dynamically supply a new HttpHandler for each call. The number of parameters
    // matches the number of dynamic sections in the path (1)
    fun greet(nameFromPath: String, foo: String): HttpHandler = { request: Request ->
        val age = ageQuery(request)
        val sentMessage = stringBody(request)

        Response(OK).with(stringBody of "hello $nameFromPath you are $age. You sent $sentMessage")
    }

    return spec to ::greet
}
foo
's value is always
"foo"
in this case According to Stack Overflow https://stackoverflow.com/questions/53278208/how-do-you-model-a-path-parameter-in-the-middle-with-http4k, it seems that the inclusion of an extra parameter is unavoidable. I also checked http4k internal implementation, and class
ContractRouteSpec2
is the reason behind the required
foo: String
. I may replace
greet
with a lambda and put
_: String
instead of
foo: String
, but just before I do the refactoring, I wanna make sure it is the intended way to handle this problem. Sorry for the superrrrr long question, and thank you reading it all the way here.
d
Yes - you're absolutely 💯. The system doesn't know the difference between a static and dynamic path element - it just matches on that value, so the art can safely be ignored. 🙃
b
Great! Thank you for the quick response. At first I found
foo: String
or
_: String
to be annoying, but http4k's OpenAPI3 integration is so useful, I guess I will just accept it
d
you're right... it is annoying! And I'm saying that as the person who wrote it - but I wasn't clever enough to make it work another way at the time. 😂
b
Are there any reason why the initial design is not like the following
Copy code
// this route has a dynamic path segment
fun greetRoute(): ContractRoute {

    // these lenses define the dynamic parts of the request that will be used in processing
    val ageQuery = <http://Query.int|Query.int>().required("age")
    val stringBody = Body.string(TEXT_PLAIN).toLens()
    val namePath = Path.of("name")

    // this specifies the route contract, with the desired contract of path, headers, queries and body parameters.
    val spec = "/greet/{name}/foo" meta {
        summary = "tells the user hello!"
        queries += ageQuery
        queries += namePath
        receiving(stringBody)
    } bindContract GET

    // the this function will dynamically supply a new HttpHandler for each call. The number of parameters
    // matches the number of dynamic sections in the path (1)
    fun greet(): HttpHandler = { request: Request ->
        val name = namePath(request)
        val age = ageQuery(request)
        val sentMessage = stringBody(request)

        Response(OK).with(stringBody of "hello $name you are $age. You sent $sentMessage")
    }

    return spec to ::greet
}
I have not read http4k implementation in detail, so I am not sure if there are any technical difficulty about it. If you have time, please enlighten me.
d
the reason for that is that you would need to add the path lenses separately to the meta instead of them being on the path automatically . It's doable, but more hassle for the user.
b
Understood😃. While I personally prefer the style I proposed, and believe that
_: String
is more annoying than manual Lens, I still appreciate the current http4k implementation and would totally keep a blind eye to
_: String
. Thank you for http4k.