Kotlin DSL http client
gradle kotlin DSL:
compile(group = "io.github.rybalkinsd", name = "kohttp", version = "0.8.0")gradle groovy DSL:
compile 'io.github.rybalkinsd:kohttp:0.8.0'maven:
<dependency>
<groupId>io.github.rybalkinsd</groupId>
<artifactId>kohttp</artifactId>
<version>0.8.0</version>
</dependency>val response: Response = "https://google.com/search?q=iphone".httpGet()val response: Response = httpGet {
host = "google.com"
path = "/search"
param {
"q" to "iphone"
"safe" to "off"
}
}or
val response: Response = httpGet {
url("https://google.com/search")
param {
"q" to "iphone"
"safe" to "off"
}
}
val response: Response = httpGet {
host = "github.com"
path = "/search"
header {
"username" to "rybalkinsd"
"security-policy" to json {
"base-uri" to "none"
"expect-ct" to json {
"max-age" to 2592000
"report-uri" to "foo.com/bar"
}
"script-src" to listOf("github.com", "github.io")
}
cookie {
"user_session" to "toFycNV"
"expires" to "Fri, 21 Dec 2018 09:29:55 -0000"
}
}
param { ... }
}form body has a application/x-www-form-urlencoded content type
val response: Response = httpPost {
host = "postman-echo.com"
path = "/post"
param { ... }
header { ... }
body {
form { // Resulting form will not contain ' ', '\t', '\n'
"login" to "user" // login=user&
"email" to "john.doe@gmail.com" // email=john.doe@gmail.com
}
}
// or
body {
form("login=user&email=john.doe@gmail.com")
}
}json body has a application/json content type
val response: Response = httpPost {
host = "postman-echo.com"
path = "/post"
param { ... }
header { ... }
body { // Resulting json will not contain ' ', '\t', '\n'
json { // {
"login" to "user" // "login": "user",
"email" to "john.doe@gmail.com" // "email": "john.doe@gmail.com"
} // }
}
// or
body {
json("""{"login":"user","email":"john.doe@gmail.com"}""")
}
}In addition to form or json body content types it is possible to declare a custom content type.
body DSL support three data sources: file(), bytes() and string()
httpPost {
body("application/json") {
string("""{"login":"user","email":"john.doe@gmail.com"}""")
}
}val imageFile = File(getResource("/cat.gif").toURI())
httpPost {
body(type = "image/gif") {
file(imageFile)
}
}httpPost {
body { // content type is optional, null by default
bytes("string of bytes".toByteArray())
}
}val response = httpPost {
url("http://postman-echo.com/post")
multipartBody {
+form("cat", File(this.javaClass.getResource("/cat.gif").toURI()))
+form("dog", File("/mydog.img"))
}
}You can use same syntax as in GET
val response = httpHead { }You can use same syntax as in POST
val response = httpPut { }You can use same syntax as in POST
val response = httpPatch { }You can use same syntax as in POST
val response = httpDelete { }You can upload file by URI or File
val fileUri = this.javaClass.getResource("/cat.gif").toURI()
val response = upload {
url("http://postman-echo.com/post")
file(fileUri)
}val file = File(this.javaClass.getResource("/cat.gif").toURI())
val response = file.upload( string or url )val fileUri = this.javaClass.getResource("/cat.gif").toURI()
val response = fileUri.upload( string or url )This function starts a new coroutine with Unconfined dispatcher.
val response: Deferred<Response> = "https://google.com/search?q=iphone".asyncHttpGet()val response: Deferred<Response> = asyncHttpGet {
host = "google.com"
path = "/search"
header { ... }
param { ... }
}Kohttp methods return okhttp3.Response which is AutoClosable
It's strictly recommended to access it with use to prevent resource leakage.
val response = httpGet { ... }
reponse.use {
...
}Kohttp provides a defaultClientPool to have a single endpoint for your http request.
It is possible to customize defaultClientPool by setting kohttp.yaml in resource directory of your project.
You can check default values in io.github.rybalkinsd.kohttp.configuration.Config.kt
All time values are in Milliseconds
client:
connectTimeout: 5000
readTimeout: 10000
writeTimeout: 10000
followRedirects: true
followSslRedirects: true
connectionPool:
maxIdleConnections: 42
keepAliveDuration: 10000Forked client uses exactly the same connection pool and dispatcher. However, it will custom parameters like custom timeouts, additional interceptors or others.
In this example below patientClient will share ConnectionPool with defaultHttpClient,
however patientClient requests will have custom read timeout.
val patientClient = defaultHttpClient.fork {
readTimeout = 100_000
}If defaultClientPool or forked client does not suit you for some reason, it is possible to create your own one.
// a new client with custom dispatcher, connection pool and ping interval
val customClient = client {
dispatcher = ...
connectionPool = ConnectionPool( ... )
pingInterval = 1_000
}Instead of .use { ... it.body?.string() ... } it is now possible to read response body as string.
And also to map Headers to listOf<Header> to operate them easily.
val response: EagerResponse = "https://google.com/search?q=iphone".httpGet().eager()
// iterating over headers
response.headers.forEach { ... }
// manipulating body
response.body?.let { ... }
val response: EagerResponse = httpGet { }.eager()
// iterating over headers
response.headers.forEach { ... }
// manipulating body
response.body?.let { ... }