HttpClientTool.kt
package com.hexagonkt.rest.tools
import com.hexagonkt.core.media.MediaType
import com.hexagonkt.core.urlOf
import com.hexagonkt.http.SslSettings
import com.hexagonkt.http.client.HttpClient
import com.hexagonkt.http.client.HttpClientPort
import com.hexagonkt.http.client.HttpClientSettings
import com.hexagonkt.http.handlers.BeforeHandler
import com.hexagonkt.http.handlers.HttpHandler
import com.hexagonkt.http.model.HttpRequest
import com.hexagonkt.http.model.*
import com.hexagonkt.http.model.HttpMethod.*
import com.hexagonkt.http.model.HttpStatusType.SUCCESS
import com.hexagonkt.http.patterns.createPathPattern
import com.hexagonkt.rest.SerializeRequestCallback
data class HttpClientTool(
val adapter: HttpClientPort,
val url: String? = null,
val httpContentType: ContentType? = null,
val httpAccept: List<ContentType> = emptyList(),
val httpHeaders: Map<String, *> = emptyMap<String, Any>(),
val sslSettings: SslSettings? = SslSettings(),
val handler: HttpHandler? = serializeHandler,
val authorization: Authorization? = null,
val followRedirects: Boolean = false
) {
companion object {
// TODO Use SerializeRequestHandler when created
val serializeHandler: HttpHandler = BeforeHandler("*", SerializeRequestCallback())
}
private val settings =
HttpClientSettings(
baseUrl = url?.let(::urlOf),
contentType = httpContentType,
accept = httpAccept,
useCookies = true,
headers = toHeaders(httpHeaders),
insecure = true,
sslSettings = sslSettings,
authorization = authorization,
followRedirects = followRedirects
)
private val client = HttpClient(adapter, settings, handler = handler)
private lateinit var lastRequest: HttpRequest
private lateinit var lastAttributes: Map<String, *>
private lateinit var lastResponse: HttpResponsePort
val request: HttpRequest get() = lastRequest
val attributes: Map<String, *> get() = lastAttributes
val response: HttpResponsePort get() = lastResponse
val status: HttpStatus get() = lastResponse.status
val body: Any get() = lastResponse.body
val cookies: Map<String, Cookie> get() = lastResponse.cookiesMap()
val headers: Headers get() = lastResponse.headers
val contentType: ContentType? get() = lastResponse.contentType
constructor(
adapter: HttpClientPort,
url: String? = null,
mediaType: MediaType,
accept: List<MediaType> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
sslSettings: SslSettings? = SslSettings(),
handler: HttpHandler? = serializeHandler,
) : this(
adapter,
url,
ContentType(mediaType),
accept.map(::ContentType),
headers,
sslSettings,
handler
)
fun start() {
if (!client.started())
client.start()
}
fun stop() {
if (client.started())
client.stop()
}
fun request(block: HttpClientTool.() -> Unit) {
client.request { block.invoke(this@HttpClientTool) }
}
fun assertStatus(status: HttpStatus) {
assert(status == lastResponse.status)
}
fun assertOk() {
assertStatus(OK_200)
}
fun assertStatus(statusType: HttpStatusType) {
assert(statusType == lastResponse.status.type)
}
fun assertSuccess() {
assertStatus(SUCCESS)
}
fun assertContentType(contentType: ContentType) {
assert(this.contentType == contentType)
}
fun assertContentType(mediaType: MediaType) {
assert(contentType == ContentType(mediaType))
}
fun assertBody(body: Any) {
assert(body == lastResponse.body)
}
fun assertBodyContains(vararg texts: String) {
texts.forEach { assert(lastResponse.bodyString().contains(it)) }
}
private fun toHeaders(map: Map<String, *>): Headers = Headers(
map.mapValues { (k, v) ->
Header(
k,
when (v) {
is Collection<*> -> v.map { it.toString() }.toList()
else -> listOf(v.toString())
}
)
}
)
private fun send(
method: HttpMethod = GET,
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
attributes: Map<String, Any> = emptyMap(),
): HttpResponsePort =
client
.apply {
if (!started())
start()
lastAttributes = attributes
lastRequest = HttpRequest(
method = method,
path = path,
body = body,
headers = toHeaders(headers),
formParameters = FormParameters(formParameters),
parts = parts,
contentType = contentType,
accept = accept,
)
}
.send(lastRequest, attributes = attributes)
.apply { lastResponse = this }
private fun send(
method: HttpMethod = GET,
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
attributes: Map<String, Any> = emptyMap(),
): HttpResponsePort =
send(
method = method,
path = createPathPattern(path.first, false).insertParameters(path.second),
body = body,
formParameters = formParameters,
headers = toHeaders(headers),
parts = parts,
contentType = contentType,
accept = accept,
attributes = attributes
+ mapOf("pathPattern" to path.first, "pathParameters" to path.second),
)
fun get(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(GET, path, body, formParameters, headers, parts, contentType, accept)
fun put(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PUT, path, body, formParameters, headers, parts, contentType, accept)
fun put(
path: String = "/",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
body: () -> Any,
): HttpResponsePort =
put(path, body(), formParameters, headers, parts, contentType, accept)
fun post(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(POST, path, body, formParameters, headers, parts, contentType, accept)
fun post(
path: String = "/",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
body: () -> Any,
): HttpResponsePort =
post(path, body(), formParameters, headers, parts, contentType, accept)
fun options(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(OPTIONS, path, body, formParameters, headers, parts, contentType, accept)
fun delete(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(DELETE, path, body, formParameters, headers, parts, contentType, accept)
fun patch(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PATCH, path, body, formParameters, headers, parts, contentType, accept)
fun trace(
path: String = "/",
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(TRACE, path, body, formParameters, headers, parts, contentType, accept)
fun get(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(GET, path, body, formParameters, headers, parts, contentType, accept)
fun put(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PUT, path, body, formParameters, headers, parts, contentType, accept)
fun put(
path: Pair<String, Map<String, Any>>,
formParameters: List<FormParameter> = emptyList(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
body: () -> Any,
): HttpResponsePort =
put(path, body(), formParameters, Headers(), parts, contentType, accept)
fun post(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(POST, path, body, formParameters, headers, parts, contentType, accept)
fun post(
path: Pair<String, Map<String, Any>>,
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
body: () -> Any,
): HttpResponsePort =
post(path, body(), formParameters, headers, parts, contentType, accept)
fun options(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(OPTIONS, path, body, formParameters, headers, parts, contentType, accept)
fun delete(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(DELETE, path, body, formParameters, headers, parts, contentType, accept)
fun patch(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PATCH, path, body, formParameters, headers, parts, contentType, accept)
fun trace(
path: Pair<String, Map<String, Any>>,
body: Any = "",
formParameters: List<FormParameter> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(TRACE, path, body, formParameters, headers, parts, contentType, accept)
}