使用 Ktor(和 Kotlin)实现 REST API 时,它支持 Kotlin 的可选字段处理。这适用于 POST 和 GET,但是 PATCH(更新)呢?
例如,您有以下资源:
@Serializable
data class MyAddress(
var line1: String? = null,
var line2: String? = null,
var city: String? = null,
var postal_code: String? = null,
var state: String? = null,
var country: String? = null
)
因此所有 MyAddress 字段都是可选的(具有默认值)。
当您使用 POST 创建地址时:
"line1" : "line1",
"country" : "XX"
并且您想要使用补丁删除该国家/地区:
"country" : null
资源的最终结果应该是:
"line1" : "line1"
但是如何通过解析 PATCH 请求的 json 来确定这一点呢?因为据我所知,没有办法确定它是否是 null
默认情况下,或已提交。
此外,默认 null
MyAddress
的值是必需的,否则解析将无法进行。
代码示例:
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
@kotlinx.serialization.Serializable
data class MyAddress(
var line1: String? = null,
var line2: String? = null,
var city: String? = null,
var postal_code: String? = null,
var state: String? = null,
var country: String? = null
)
fun main() {
val jsonStringPOST = "{\"line1\":\"street\",\"country\":\"GB\"}"
println("JSON string is: $jsonStringPOST")
val myAddressPost = Json.decodeFromString<MyAddress>(jsonStringPOST)
println("MyAddress object: $myAddressPost")
val jsonStringPATCH = "{\"country\":null}"
println("JSON string is: $jsonStringPATCH")
val myAddressPatch = Json.decodeFromString<MyAddress>(jsonStringPATCH)
println("MyAddress object: $myAddressPatch")
}
我尝试添加Optional<String>?
同样,但它提示缺少 Optional
的序列化,并且最好我不想将所有数据设为 var 的可选值。
注意:我正在寻找一种更加结构化的解决方案,该解决方案也适用于 API 中的所有其他资源(10 多个类)。
最佳答案
第二个解决方案,基于 Aleksei 的示例:
@Serializable
data class Address2(val line1: OptionalValue<String> = Undefined, val country: OptionalValue<String> = Undefined)
@Serializable(with = OptionalValueSerializer::class)
sealed interface OptionalValue<out T>
object Undefined: OptionalValue<Nothing> {
override fun toString(): String = "Undefined"
}
object Absent: OptionalValue<Nothing> {
override fun toString(): String = "Absent"
}
class WithValue<T>(val value: T): OptionalValue<T> {
override fun toString(): String = value.toString()
}
open class OptionalValueSerializer<T>(private val valueSerializer: KSerializer<T>) : KSerializer<OptionalValue<T>> {
override val descriptor: SerialDescriptor = valueSerializer.descriptor
override fun deserialize(decoder: Decoder): OptionalValue<T> {
return try {
WithValue(valueSerializer.deserialize(decoder))
} catch (cause: SerializationException) {
Absent
}
}
override fun serialize(encoder: Encoder, value: OptionalValue<T>) {
when (value) {
is Undefined -> {}
is Absent -> { encoder.encodeNull() }
is WithValue -> valueSerializer.serialize(encoder, value.value)
}
}
}
fun main() {
val jsonStringPOST = "{\"line1\":\"street\",\"country\":\"GB\"}"
println("JSON string is: $jsonStringPOST")
val myAddressPost = Json.decodeFromString<Address2>(jsonStringPOST)
println("MyAddress object: $myAddressPost")
val jsonStringUPDATE = "{\"country\":null}"
println("JSON string is: $jsonStringUPDATE")
val myAddressUpdate = Json.decodeFromString<Address2>(jsonStringUPDATE)
println("MyAddress object: $myAddressUpdate")
if(myAddressUpdate.country is Absent || myAddressUpdate.country is WithValue) {
println("Update country: ${myAddressUpdate.country}")
} else {
println("No update for country: ${myAddressUpdate.country}")
}
}
输出是:
JSON string is: {"line1":"street","country":"GB"}
MyAddress object: Address2(line1=street, country=GB)
JSON string is: {"country":null}
MyAddress object: Address2(line1=Undefined, country=Absent)
Update country: Absent
关于rest - Kotlin - Ktor - 如何处理 PATCH 调用中的可选 API 资源字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72856270/