Kotlin DSL http client (okhttp frontend)
Clone or download
Latest commit 8323e1a Jan 10, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
gradle/wrapper initial Dec 18, 2018
src Release/0.7.0 (#59) Jan 7, 2019
.gitignore json dsl Jul 25, 2018
.travis.yml 1. mv to openjdk Nov 1, 2018
LICENSE LICENCE Jul 22, 2018
README.md #66 fix (#67) Jan 10, 2019
build.gradle.kts #66 fix (#67) Jan 10, 2019
gradlew travis build fix with providing gradlew Jul 22, 2018
gradlew.bat travis build fix with providing gradlew Jul 22, 2018
settings.gradle initial Jul 20, 2018

README.md

Kotlin dsl for OkHttp

Build Status Maven Central codecov Codacy Badge Kotlin Awesome Kotlin Badge

Kotlin DSL http client

Download

gradle kotlin DSL:

compile(group = "io.github.rybalkinsd", name = "kohttp", version = "0.7.1")

gradle groovy DSL:

compile 'io.github.rybalkinsd:kohttp:0.7.1'

maven:

<dependency>
  <groupId>io.github.rybalkinsd</groupId>
  <artifactId>kohttp</artifactId>
  <version>0.7.1</version>
</dependency>

Usage

Sync http calls

GET

String.httpGet() extension
val response: Response = "https://google.com/search?q=iphone".httpGet()
GET with request parameters
val response: Response = httpGet {
   host = "google.com"
   path = "/search"
   param {
       "q" to "iphone"
       "safe" to "off"
   }
}
GET with header and cookies
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 { ... }
}

POST

POST with form body.

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")
    }
}
POST with json body.

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"}""")
    }
}
POST with various content type

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())
    }
}

HEAD

You can use same syntax as in GET

val response = httpHead { }

PUT

You can use same syntax as in POST

val response = httpPut { }

PATCH

You can use same syntax as in POST

val response = httpPatch { }

DELETE

You can use same syntax as in POST

val response = httpDelete { }

Async http calls

async GET

String.asyncHttpGet() extension function

This function starts a new coroutine with Unconfined dispatcher.

val response: Deferred<Response> = "https://google.com/search?q=iphone".asyncHttpGet()
asyncHttpGet call
val response: Deferred<Response> = asyncHttpGet {
    host = "google.com"
    path = "/search"
    header { ... }
    param { ... }
}

Response usage

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 {
    ...
}

Customization

defaultClientPool customization

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: 10000

Fork HttpClient for specific tasks

Forked 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 
}

Run HTTP methods on custom client

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
}

Experimental

Eager response

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 { ... }