Kotlin DSL http client
gradle kotlin DSL:
implementation(group = "io.github.rybalkinsd", name = "kohttp", version = "0.10.0")
gradle groovy DSL:
implementation 'io.github.rybalkinsd:kohttp:0.10.0'
maven:
<dependency>
<groupId>io.github.rybalkinsd</groupId>
<artifactId>kohttp</artifactId>
<version>0.10.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 "[email protected]" // [email protected]
}
}
// or
body {
form("login=user&[email protected]")
}
}
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 "[email protected]" // "email": "[email protected]"
} // }
}
// or
body {
json("""{"login":"user","email":"[email protected]"}""")
}
}
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":"[email protected]"}""")
}
}
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())
}
}
Content type is set according to the following priority levels (higher is prioritized)
- Form or Json in body :
kotlin ... body() { json { ... } } ...
- Custom body type :
kotlin ... body(myContentType) { ... } ...
- Header :
kotlin ... header { "Content-type" to myContentType } ...
val response = httpPost {
url("http://postman-echo.com/post")
multipartBody {
+part("meta") {
json {
"token" to "$token"
}
}
+part("image") {
file(imageFile)
}
}
}
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
. Upload DSL can include headers
and params
.
val fileUri = this.javaClass.getResource("/cat.gif").toURI()
val response = upload {
url("http://postman-echo.com/post")
file(fileUri)
headers {
...
cookies {...}
}
params {...}
}
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".httpGetAsync()
You can use same syntax as in GET
val response: Deferred<Response> = httpGetAsync { }
You can use same syntax as in POST
val response: Deferred<Response> = httpPostAsync { }
You can use same syntax as in GET
val response: Deferred<Response> = httpHeadAsync { }
You can use same syntax as in POST
val response: Deferred<Response> = httpPutAsync { }
You can use same syntax as in POST
val response: Deferred<Response> = httpPatchAsync { }
You can use same syntax as in POST
val response: Deferred<Response> = httpDeleteAsync { }
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 {
...
}
Response body can be retrieved as a JSON
, String
or InputStream
using provided extension functions on Response
.
val response = httpGet { ... }
val dataAsJson: JsonNode = response.asJson()
val dataAsString: String? = response.asString()
val dataAsStream: InputStream? = response.asStream()
Kohttp provides a DSL to add interceptors. Custom Interceptors can be defined by implementing the okhttp3.Interceptors
. Interceptors are added by forking the defaultHttpClient
.
val forkedClient = defaultHttpClient.fork {
interceptors {
+interceptor1
+interceptor2
}
}
-
Logging Interceptor: A Request Logging Interceptor.
Parameters:
strategy: LoggingStrategy = HttpLoggingStrategy()
: Formatting strategy: CURL / HTTPlog: (String) -> Unit = ::println
: function as a parameter to consume the log message. It defaults toprintln
. Logs Request body when present.
Usage:
val client = defaultHttpClient.fork { interceptors { +LoggingInterceptor() } }
Sample Output:
[2019-01-28T04:17:42.885Z] GET 200 - 1743ms https://postman-echo.com/get
-
Retry Interceptor: Provides a configurable method to retry on specific errors.
Parameters:
failureThreshold: Int
: Number of attempts to get response with. Defaults to3
.invocationTimeout: Long
: timeout (millisecond) before retry. Defaults to0
ratio: Int
: ratio for exponential increase of invocation timeout. Defaults to1
errorStatuses: List<Int>
: HTTP status codes to be retried on. Defaults to listOf(503, 504)
Usage:
val client = defaultHttpClient.fork { interceptors { +RetryInterceptor() } }
-
Signing Interceptor: Enables signing of query parameters. Allowing creation of presigned URLs.
Parameters:
parameterName: String
: The name of the parameter with signed keysigner: HttpUrl.() -> String
: Function withokhttp3.HttpUrl
as a receiver to sign the request parameter
Usage:
val client = defaultHttpClient.fork { interceptors { +SigningInterceptor("key") { val query = (query() ?: "").toByteArray() urlEncoder.encodeToString(md5.digest(query)) } } }
Kohttp provides a defaultClientPool
to have a single endpoint for your http request.
Forked client uses exactly the same connection pool and dispatcher. However, it will custom parameters like custom timeout
s, additional interceptor
s 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
}