nilTheDev
10/30/2021, 8:34 AMcall.receiveOrNull<T>()
isn't working as expected. This is how you can reproduce,
1. Install the ContentNegotiation
plugin for automatic deserialization of json
content. (I am using kotlinx.serialization
)
2. Define a model for the expected data
3. Send request with missing json field
4. Instead of returning null, it's throwing the exception and causing a 500 internal server error
Code,
fun Application.module() {
install(ContentNegotiation) {
json(
Json { ignoreUnknownKeys = true }
)
}
routing {
post("/") {
val user = call.receiveOrNull<User>()
?: return@post call.respondText(
text = "invalid request",
status = HttpStatusCode.BadRequest
)
call.respondText(text = "valid request", status = HttpStatusCode.Accepted)
}
}
}
Model,
@Serializable
data class User(
@SerialName("username")
val userName: String,
val password: String
)
Sent request,
POST / HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 24
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.5.0
{
"username": "nilanjan"
}
Received response,
HTTP/1.1 500 Internal Server Error
Connection: keep-alive
Content-Length: 0
Exception thrown in the server,
kotlinx.serialization.MissingFieldException: Field 'password' is required for type with serial name 'com.jetbrains.handson.httpapi.User'
As a workaround I had to define my own receiveOrNull
extension function.
suspend inline fun <reified T : Any> ApplicationCall.receiveOrNull(): T? {
return try {
receive<T>()
} catch (cause: Exception) {
null
}
}
The actual receiveOrNull
function in the io.ktor.request
package looks like that,
public suspend fun <T : Any> ApplicationCall.receiveOrNull(type: KType): T? {
return try {
receive<T>(type)
} catch (cause: ContentTransformationException) {
application.log.debug("Conversion failed, null returned", cause)
null
}
}
Apparently, it's only catching the ContentTransformationException
nothing else.
This issue in YourTrack is similar to my issue,
https://youtrack.jetbrains.com/issue/KTOR-545
So, my questions are,
1. Is this how the receiveOrNull
function supposed to work? Or it is a bug? Do I have to report it?
2. If it's not a bug then why it is designed this way? Isn't it a good design to catch all kind of errors related to deserialization in the receiveOrNull
function rather than causing an internal server error?andylamax
10/30/2021, 8:55 AMenleur
10/30/2021, 10:50 AMnilTheDev
10/30/2021, 12:37 PMenleur
10/30/2021, 12:42 PMnilTheDev
10/30/2021, 12:43 PMenleur
10/30/2021, 12:46 PMAleksei Tirman [JB]
11/01/2021, 8:29 AMnull
only if a suitable converter isn't found so the transformation isn't applied. The server responds with the 500 status code because it's the default behavior for any uncaught exceptions and it's overridable by the StatusPages plugin.