1.0.1
. implementation "io.ktor:ktor-client-core:1.0.1" implementation "io.ktor:ktor-client-android:1.0.1"
<uses-permission android:name="android.permission.INTERNET"/>
private const val BASE_URL = "https://httpbin.org" private const val GET_UUID = "$BASE_URL/uuid" fun simpleCase() { val client = HttpClient() GlobalScope.launch(Dispatchers.IO) { val data = client.get<String>(GET_UUID) Log.i("$BASE_TAG Simple case ", data) } }
HttpClient()
. In this case, Ktor will select the required engine himself and use it with the default settings (we have one connected engine - Android, but there are others, for example, OkHttp).get()
is a suspend
function. fun performAllCases() { GlobalScope.launch(Dispatchers.IO) { simpleCase() bytesCase() } } suspend fun simpleCase() { val client = HttpClient() val data = client.get<String>(GET_UUID) Log.i("$BASE_TAG Simple case", data) } suspend fun bytesCase() { val client = HttpClient() val data = client.call(GET_UUID).response.readBytes() Log.i("$BASE_TAG Bytes case", data.joinToString(" ", "[", "]") { it.toString(16).toUpperCase() }) }
HttpClient
methods are HttpClient
, such as call()
and get()
, await()
will be called under the hood. So in this case, the calls simpleCase()
and bytesCase()
will always be consistent. It is necessary in parallel - just wrap each call into a separate coruntine. In this example, new methods have appeared. A call(GET_UUID)
will return to us an object from which we can get information about the request, its configuration, response, and customer. The object contains a lot of useful information - from the response code and the protocol version to the channel with the same bytes.close()
method on the client. If you need to make one call and immediately close the client, you can use the use{}
method, since HttpClient
implements the Closable
interface. suspend fun closableSimpleCase() { HttpClient().use { val data: String = it.get(GET_UUID) Log.i("$BASE_TAG Closable case", data) } }
POST
. Consider the example of setting parameters, headers and the request body. suspend fun postHeadersCase(client: HttpClient) { val data: String = client.post(POST_TEST) { fillHeadersCaseParameters() } Log.i("$BASE_TAG Post case", data) } private fun HttpRequestBuilder.fillHeadersCaseParameters() { parameter("name", "Andrei") // + url.parameters.appendAll( parametersOf( "ducks" to listOf("White duck", "Grey duck"), // + "fish" to listOf("Goldfish") // + ) ) header("Ktor", "https://ktor.io") // + headers /* */ { append("Kotlin", "https://kotl.in") } headers.append("Planet", "Mars") // + headers.appendMissing("Planet", listOf("Mars", "Earth")) // + , "Mars" headers.appendAll("Pilot", listOf("Starman")) // body = FormDataContent( // , form Parameters.build { append("Low-level", "C") append("High-level", "Java") } ) }
post()
function, you have access to the HttpRequestBuilder
, with which you can create any request.post()
method simply parses the string, converts it to a URL, explicitly specifies the type of the method, and makes the request. suspend fun rawPostHeadersCase(client: HttpClient) { val data: String = client.call { url.takeFrom(POST_TEST) method = HttpMethod.Post fillHeadersCaseParameters() } .response .readText() Log.i("$BASE_TAG Raw post case", data) }
put()
, delete()
, patch()
, head()
and options()
, so we will not consider them.call()
you get a low-level response and you have to read the data yourself, but what about automatic typing? After all, we are all used to connect a converter in Retrofit2 (such as Gson
) and specify the return type as a specific class. We'll talk about conversion into classes later, but the request
method will help typify the result without being tied to a specific HTTP method. suspend fun typedRawPostHeadersCase(client: HttpClient) { val data = client.request<String>() { url.takeFrom(POST_TEST) method = HttpMethod.Post fillHeadersCaseParameters() } Log.i("$BASE_TAG Typed raw post", data) }
HttpRequestBuilder
. But it can be easier.submitForm
function accepts a url as a string, parameters for a query, and a boolean flag that tells you how to pass parameters — in the query string or as pairs in a form. suspend fun submitFormCase(client: HttpClient) { val params = Parameters.build { append("Star", "Sun") append("Planet", "Mercury") } val getData: String = client.submitForm(GET_TEST, params, encodeInQuery = true) // val postData: String = client.submitForm(POST_TEST, params, encodeInQuery = false) // form Log.i("$BASE_TAG Submit form get", getData) Log.i("$BASE_TAG Submit form post", postData) }
suspend fun submitFormBinaryCase(client: HttpClient) { val inputStream = ByteArrayInputStream(byteArrayOf(77, 78, 79)) val formData = formData { append("String value", "My name is") // append("Number value", 179) // append("Bytes value", byteArrayOf(12, 74, 98)) // append("Input value", inputStream.asInput(), headersOf("Stream header", "Stream header value")) // } val data: String = client.submitFormWithBinaryData(POST_TEST, formData) Log.i("$BASE_TAG Submit binary case", data) }
buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" } } allprojects { repositories { maven { url "https://kotlin.bintray.com/kotlinx" } } }
apply plugin: 'kotlinx-serialization' dependencies { implementation "io.ktor:ktor-client-json-jvm:1.0.1" implementation "io.ktor:ktor-client-gson:1.0.1" }
data class Weather( val consolidated_weather: List<ConsolidatedWeather>, val time: String, val sun_rise: String, val sun_set: String, val timezone_name: String, val parent: Parent, val sources: List<Source>, val title: String, val location_type: String, val woeid: Int, val latt_long: String, val timezone: String ) data class Source( val title: String, val slug: String, val url: String, val crawl_rate: Int ) data class ConsolidatedWeather( val id: Long, val weather_state_name: String, val weather_state_abbr: String, val wind_direction_compass: String, val created: String, val applicable_date: String, val min_temp: Double, val max_temp: Double, val the_temp: Double, val wind_speed: Double, val wind_direction: Double, val air_pressure: Double, val humidity: Int, val visibility: Double, val predictability: Int ) data class Parent( val title: String, val location_type: String, val woeid: Int, val latt_long: String ) private const val SF_WEATHER_URL = "https://www.metaweather.com/api/location/2487956/" suspend fun getAndPrintWeather() { val client = HttpClient(Android) { install(JsonFeature) { serializer = GsonSerializer() } } val weather: Weather = client.get(SF_WEATHER_URL) Log.i("$BASE_TAG Serialization", weather.toString()) }
BadResponseStatus
error is BadResponseStatus
. It is enough to set the expectSuccess
client to true
when building the client. val client = HttpClient(Android) { install(JsonFeature) { serializer = GsonSerializer() } expectSuccess = true }
implementation "io.ktor:ktor-client-logging-jvm:1.0.1"
val client = HttpClient(Android) { install(Logging) { logger = Logger.DEFAULT level = LogLevel.ALL } }
Source: https://habr.com/ru/post/432310/
All Articles