HttpClientTool.kt
package com.hexagontk.rest.tools
import com.hexagontk.core.media.MediaType
import com.hexagontk.http.SslSettings
import com.hexagontk.http.client.HttpClient
import com.hexagontk.http.client.HttpClientPort
import com.hexagontk.http.client.HttpClientSettings
import com.hexagontk.http.handlers.BeforeHandler
import com.hexagontk.http.handlers.HttpHandler
import com.hexagontk.http.model.HttpRequest
import com.hexagontk.http.model.*
import com.hexagontk.http.model.HttpMethod.*
import com.hexagontk.http.patterns.createPathPattern
import com.hexagontk.rest.SerializeRequestCallback
import java.net.URI
class HttpClientTool(
adapter: HttpClientPort,
url: String? = null,
httpContentType: ContentType? = null,
httpAccept: List<ContentType> = emptyList(),
val httpHeaders: Map<String, *> = emptyMap<String, Any>(),
sslSettings: SslSettings? = SslSettings(),
val handler: HttpHandler? = serializeHandler,
authorization: Authorization? = null,
followRedirects: Boolean = false
) {
companion object {
// TODO Use SerializeRequestHandler when created
val serializeHandler: HttpHandler = BeforeHandler("*", SerializeRequestCallback())
}
private val settings =
HttpClientSettings(
baseUri = url?.let(::URI),
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 lastResponse: HttpResponsePort
val request: HttpRequest get() = lastRequest
val response: HttpResponsePort get() = lastResponse
val status: Int 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: Int) {
assert(status == lastResponse.status)
}
fun assertOk() {
assertStatus(OK_200)
}
fun assertSuccess() {
assert(lastResponse.status in SUCCESS)
}
fun assertContentType(contentType: ContentType) {
assert(this.contentType?.text == contentType.text)
}
fun assertContentType(mediaType: MediaType) {
assertContentType(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.flatMap { (k, v) ->
when (v) {
is Collection<*> -> v.map { Header(k, it) }.toList()
else -> listOf(Header(k, v))
}
}
)
private fun send(
method: HttpMethod,
path: String?,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
pathPattern: String? = null,
pathParameters: Map<String, Any> = emptyMap(),
): HttpResponsePort =
client
.apply {
if (!started())
start()
val (pattern, patternPath) = when {
pathPattern != null ->
createPathPattern(pathPattern)
.let { it to it.insertParameters(pathParameters) }
else -> null to (path ?: "")
}
lastRequest = HttpRequest(
method = method,
path = patternPath,
body = body,
headers = toHeaders(headers),
formParameters = Parameters(formParameters),
parts = parts,
contentType = contentType,
accept = accept,
pathPattern = pattern,
pathParameters = pathParameters,
)
}
.send(lastRequest)
.apply { lastResponse = this }
private fun send(
method: HttpMethod,
pathPattern: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(
method,
null,
body,
formParameters,
headers,
parts,
contentType,
accept,
pathPattern,
pathParameters,
)
fun get(
path: String = "/",
body: Any = "",
formParameters: List<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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<HttpField> = 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: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(GET, path, pathParameters, body, formParameters, headers, parts, contentType, accept)
fun put(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PUT, path, pathParameters, body, formParameters, headers, parts, contentType, accept)
fun put(
path: String,
pathParameters: Map<String, Any>,
formParameters: List<HttpField> = emptyList(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
body: () -> Any,
): HttpResponsePort =
put(
path,
pathParameters,
body(),
formParameters,
mapOf<String, Any>(),
parts,
contentType,
accept
)
fun post(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(POST, path, pathParameters, body, formParameters, headers, parts, contentType, accept)
fun post(
path: String,
pathParameters: Map<String, Any>,
formParameters: List<HttpField> = 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, pathParameters, body(), formParameters, headers, parts, contentType, accept)
fun options(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(
OPTIONS, path, pathParameters, body, formParameters, headers, parts, contentType, accept
)
fun delete(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(
DELETE, path, pathParameters, body, formParameters, headers, parts, contentType, accept
)
fun patch(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(PATCH, path, pathParameters, body, formParameters, headers, parts, contentType, accept)
fun trace(
path: String,
pathParameters: Map<String, Any>,
body: Any = "",
formParameters: List<HttpField> = emptyList(),
headers: Map<String, *> = emptyMap<String, Any>(),
parts: List<HttpPart> = emptyList(),
contentType: ContentType? = settings.contentType,
accept: List<ContentType> = settings.accept,
): HttpResponsePort =
send(TRACE, path, pathParameters, body, formParameters, headers, parts, contentType, accept)
}