Všetky volania HttpClient-a potrebujeme volať v takzvanom coroutine scope, aby neblokovali používateľské rozhranie.
Pozrime si ukážku priamo pre GET request na IP adresu zo stránky https://api.ipify.org:
// ocakavana odpoved z BE
@Serializable
data class IpResponse(val ip: String)
// ziskaj coroutine scope, pre pracu na samostatnom threade
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
// spusti pracu na pozadi
coroutineScope.launch {
val response = client // pouzi globalne definovaneho klienta
.get("https://api.ipify.org?format=json") // zavolaj GET request na tuto url
.body<IpResponse>() // odpoved preved na IpResponse objekt
}
}) { Text("Click me") }
// response = IpResponse(ip=123.123.123.123)
Pre testovanie použijeme globálne dostupné API, ktoré simuluje pridanie poznámky do databázy.
@Serializable
data class AddTodoRequest(
val todo: String,
val completed: Boolean,
val userId: Int
)
@Serializable
data class AddTodoResponse(
val id: Int,
val todo: String,
val completed: Boolean,
val userId: Int,
)
val response = client.post("https://dummyjson.com/todos/add") {
setBody(AddTodoRequest(todo = "Click me", completed = false, userId = 1))
contentType(ContentType.Application.Json)
}.body<AddTodoResponse>()
// response = AddTodoResponse(id=255, todo=Click me, completed=false, userId=1)
Chyby samozrejme môžu nastať a vyriešiť ich môžeme klasickým try-catch blokom:
try {
val response = client.get(/**/)
} catch (e: ClientRequestException) {
// chyba requestu na strane klienta (400vky)
} catch (e: ServerResponseException) {
// server odpovedal chybou (500vky)
} catch (e: SerializationException) {
// mas zle nastavenu serializaciu
} catch (e: IOException) {
// pravdepodobne chyba internetoveho pripojenia
}
Ja mám radšej vlastnú sealed triedu a pomocnú funkciu:
sealed interface Error : ApiResult<Nothing> {
data class ServerError(val error: ServerResponseException) : Error
data class ClientError(val error: ClientRequestException) : Error
data class SerializationError(val error: SerializationException) : Error
object NoInternet : Error
data class Unknown(val error: Throwable) : Error
}
fun Throwable.toApiError(): Error = when (val e = this) {
is CancellationException -> throw e
is ClientRequestException -> Error.ClientError(e)
is ServerResponseException -> Error.ServerError(e)
is SerializationException -> Error.SerializationError(e)
is IOException -> Error.NoInternet
else -> Error.Unknown(e)
}
try {
val response = client.get(/**/)
} catch (e: Exception) {
val error = e.toApiError()
}