<@UC01FS1C3> the way I see it you've got a couple ...
# http4k
d
@Riku the way I see it you've got a couple of options, depending on what you want to achieve. First question is - how are you going to present the errors back in the response? If you upgrade to 3.112.0 of http4k you'll see that there is now a default format of the errors (in JSON format for the OpenAPI renderer). Amusingly, this was previously written but just never plugged in to the actual contract framework - so thank you for leading us in that direction to plug it in! The default 400 response implementation looks like this - note that the body parameter would appear as a single failure in the case you've already uncovered:
Copy code
{
  "message": "Missing/invalid parameters",
  "params": [
    {
      "name": "name1",
      "type": "query",
      "datatype": "string",
      "required": true,
      "reason": "Missing"
    },
    {
      "name": "name2",
      "type": "header",
      "datatype": "number",
      "required": false,
      "reason": "Invalid"
    }
  ]
}
If you want to override that behaviour, you can subclass
OpenAPI
and simply provide your own
badRequest()
and
notFound()
methods In terms of unmarshalling, there are distinct phases: 1. Are all the properties in the JSON there? 2. Are they valid? Unfortunately, as you've found out - if you lean on the type system to detect missing non-nullable properties, you'll end up with a message (as the Jackon will blow up during deserialisation), which you could possibly deconstruct looking for the "reference chain". One other option is to make all the fields nullable - possibly with an intermediate unvalidated version of your DTO. It's similar for invalid properties - if you add custom unmarshalling for each property type (eg. through micro/tiny-types - probably simple wrapper classes which blow up during construction) you'll end up with the same type of message. If you really wanted total control, I'd probably recommend going for an intermediate step of unmarshalling the object to a JSON Node tree first, then coming up with a validation/conversion step to turn that tree into the end DTO. This step would collect the errors and then throw a LensFailure containing the collected errors upon failure. So something like:
Copy code
Body.json().map({ json -> EntityDTO.from(json) }).toLens()
You are in this case losing the convenience of the full auto-marshalling, but swapping that for the granular validation. One other thing with this approach is that you could use the Jackson instance to selectively unmarshall sub-trees of your object and then provide messages if that mini-conversion fails. Hope that (somewhat) makes sense. As ever, if it doesn't please just ask ­čÖé