I want to deserialize a form submission from a `ww...
# http4k
c
I want to deserialize a form submission from a
www-form-urlencoded
POST body received by a http4k server to a
data class
, preferably with
kotlinx.serialization
. I've done this before (when not using http4k) with Jackson, using quite some self written code, to (1) create a little language for adding structure to the form's
name
values (this allowed me to have nested data structures, and list/arrays, like
.user.permissions[5]
) and to parse the data directly to Jackson's internal JSON representation (in order to skip a JSON format step: Jackson was mainly used for it's "type coercion" since all values are received in one big
www-form-urlencoded
string). Is there anything in http4k to make this easier? I've seen the body lens feature, but I have not been able to use it for form submissions.
d
There isn't anything build in explicitly for this, but you could create something without too much effort I think. The problem you might have is that a JSON body effectively deserialises into a
Map<String, Any>
whereas the form body would deserialise into
Map<String, String>
. So - whatever you're using to deserialise needs to work around that conversion. Assuming that you can work around that, you can use the
httpBodyRoot()
function to create a custom lens creation method. Here's the standard webform version (your one would be much simpler):
Copy code
fun Body.Companion.webForm(
    validator: Validator,
    contentNegotiation: ContentNegotiation,
    vararg formFields: Lens<WebForm, *>
): BiDiBodyLensSpec<WebForm> =
    httpBodyRoot(formFields.map { it.meta }, APPLICATION_FORM_URLENCODED, contentNegotiation)
        .map({ it.payload.asString() }, { Body(it) })
        .map(
            { WebForm(formParametersFrom(it), emptyList()) },
            { (fields) -> fields.flatMap { pair -> pair.value.map { pair.key to it } }.toUrlFormEncoded() })
        .map(
            { it.copy(errors = validator(it, formFields.toList())) },
            { it.copy(errors = validator(it, formFields.toList())) })
For standard and multipart webforms, you use
Body.webform().toLens()
for the form and then
<http://FormField.int|FormField.int>().required("whatever")
etc.
c
Thanks, I'll have a look at that approach