https://kotlinlang.org logo
#http4k
Title
# http4k
v

Vojtěch Knyttl

12/06/2020, 7:22 AM
I am trying to extract better error message from Jackson deserialization of request Body - within
Filter
implemented in the example I am only getting
400 BAD REQUEST
whereas Jackson provides a nice error description. Is it possible to get this very description to log within the logging filter? https://gist.github.com/knyttl/bd0ffe5474e14a9e64f71d78249bac5b
d

dave

12/06/2020, 8:02 AM
Yep. Catch the LensFailure that is thrown and you will be able to get the message from there. You'll have to wrap the handler that is returned in the bindContract call instead of wrapping the contract itself. (Because the contract handler also contains a catch filter)
v

Vojtěch Knyttl

12/06/2020, 9:11 AM
I tried googling and find this:
Copy code
val jsonResultLens = Body.json().toLens().asResult()
    val jsonResult: Result<JsonNode, LensFailure> = jsonResultLens(Request(GET, "/foo"))
    println(jsonResult)
is this what you meant? using
jsonResultLens
within the filter? however the method
.asResult()
seems to be missing - hasn't it been removed?
d

dave

12/06/2020, 9:26 AM
Result wasn't removed. but you do need to include result4k manually. However, this will do what you want: https://gist.github.com/daviddenton/49d397479f2bf7e3ba48182d0a783483
also - one more thing - when you're posting Gists, please include an entire runnable example including imports so that it's easy for everyone to run exactly the same thing instead of having to rewrite it. 🙂
v

Vojtěch Knyttl

12/06/2020, 9:35 AM
okay, will do next time
hm in fact - i don't get any exception
no lensfailure
just response=400, message "400 BAD REQUEST"
Copy code
val loggingFilter = Filter { next: HttpHandler ->
            { request: Request ->
                val response = next(request)
                <http://log.info|log.info>(response.status.description)
                // 400 BAD_REQUEST, no error details
                response
            }
        }
you can see here, that this is just response.status, no LensFailure exception
I think your example throws LensFailure on response.body, i have issues with request.body
d

dave

12/06/2020, 9:57 AM
Set the pre extraction to no body. It's not getting to the handler (my example didn't declare the input lens)
And yes - another reason to always use full examples. 😉
v

Vojtěch Knyttl

12/06/2020, 10:42 AM
updated: https://gist.github.com/knyttl/2f380a060e3cf4f86baeecab5ce24096 however still no exception, only 400 BAD REQUEST
(I also tried
PreFlightExtraction.Companion.None
, but still no exception within the logging filter)
d

dave

12/06/2020, 10:50 AM
that's because you're still not trapping the error. look again at the Gist I sent. 🙂
v

Vojtěch Knyttl

12/06/2020, 11:19 AM
trapping the erorr
you mean the exception catching here:
Copy code
try {
                next(it)
            } catch( e: LensFailure){
                Response(BAD_REQUEST).body(e.cause?.localizedMessage ?: "")
            }
?
there is no exception thrown
d

dave

12/06/2020, 11:22 AM
The output of: https://gist.github.com/daviddenton/49d397479f2bf7e3ba48182d0a783483 on my machine is:
Copy code
HTTP/1.1 400 Bad Request


Unexpected end-of-input: was expecting closing quote for a string value
 at [Source: (String)"{"name":"}"; line: 1, column: 11] (through reference chain: Blob["name"])
v

Vojtěch Knyttl

12/06/2020, 11:22 AM
Copy code
fun CatchLensFailure(failResponseFn: (LensFailure) -> Response = {
        Response(BAD_REQUEST.description(it.failures.joinToString("; ")))
    }) = Filter { next ->
        {
            try {
                next(it)
            } catch (lensFailure: LensFailure) {
                when {
                    lensFailure.target is Response -> throw lensFailure
                    lensFailure.target is RequestContext -> throw lensFailure
                    lensFailure.overall() == Failure.Type.Unsupported -> Response(UNSUPPORTED_MEDIA_TYPE)
                    else -> failResponseFn(lensFailure)
                }
            }
        }
    }
It seems it ends here in the
else
branch - it catches the exception and retruns response
in your gist you do it differently - i need the filter to be out of the handler (i want to have it general for all handlers), note I have
loggingFilter.then(handler)(request)
d

dave

12/06/2020, 11:26 AM
yes. that's not supported
because you can't override the CatchLensFailure inside the contract handler
v

Vojtěch Knyttl

12/06/2020, 11:28 AM
sso basically i cannot have general filter which would look after all lensexceptions
d

dave

12/06/2020, 11:28 AM
basically
v

Vojtěch Knyttl

12/06/2020, 11:28 AM
and there is no way to overcome this?
d

dave

12/06/2020, 11:29 AM
not at the moment
v

Vojtěch Knyttl

12/06/2020, 7:21 PM
does it make sense to you if I create an issue for it?
d

dave

12/07/2020, 4:00 AM
Actually - I'm being an idiot. There is a way to customise it - you need to provide your own ErrorResponsrRenderer - https://github.com/http4k/http4k/blob/55ae8008df9500203fc1bfe05f244c3da58992c1/http4k-contract/src/main/kotlin/org/http4k/contract/openapi/v3/OpenApi3.kt#L54
Completely forgot about that. 🤣
(But it won’t work in any example where you don’t set the renderer up)
v

Vojtěch Knyttl

12/07/2020, 9:08 AM
hmm, but doesn't this seem to work only for OpenApi? does it mean, that once I setup OpenApi, this will start to work?
🙂 thanks, will try
3 Views