decodeValidationReason

Decodes one RequestValidationException reason. This is what requestValidation does internally for every entry of errors[]. It is exposed so a mapping that needs a shape requestValidation cannot produce — a typed errors[] element, differently named members, an extra member per entry — can still read ValidationReason.pointer/ValidationReason.detail back out of a reason built by invalidField/invalidFields, instead of re-inventing the encoding.

See also

Samples

install(RequestValidation) {
    validate<String> { body ->
        if (body.isBlank()) {
            invalidFields(
                "#/age" to "must be a positive integer",
                "#/profile/color" to "must be 'green', 'red' or 'blue'",
            )
        } else {
            ValidationResult.Valid
        }
    }
}

install(StatusPages) {
    problemDetails {
        // Bypasses requestValidation(): its errors[] shape is fixed to detail/pointer, renameable
        // but not restructured. decodeValidationReason() still reads the pointer/detail that
        // invalidFields() encoded. encodeToProblemValue() turns the typed entry into a ProblemValue.
        map<RequestValidationException> { _, cause ->
            Problem(
                type = ValidationError.typeUri,
                status = ValidationError.status,
                title = ValidationError.title,
                extensions =
                    mapOf(
                        "errors" to
                            ProblemArray(
                                cause.reasons.map { reason ->
                                    val decoded = decodeValidationReason(reason)
                                    Json.encodeToProblemValue(
                                        ValidationErrorEntry(
                                            code = "VALIDATION_FAILED",
                                            field = decoded.pointer,
                                            message = decoded.detail,
                                        ),
                                    )
                                },
                            ),
                    ),
            )
        }
    }
}

routing {
    post("/customers") {
        call.respond(call.receive<String>())
    }
}