aboutsummaryrefslogtreecommitdiff
path: root/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
diff options
context:
space:
mode:
Diffstat (limited to 'shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt')
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt58
1 files changed, 45 insertions, 13 deletions
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
index c44d473..91d0aa2 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
@@ -4,10 +4,17 @@ import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.json.*
+import io.ktor.client.features.json.serializer.KotlinxSerializer
+import io.ktor.client.features.logging.DEFAULT
+import io.ktor.client.features.logging.LogLevel
+import io.ktor.client.features.logging.Logger
+import io.ktor.client.features.logging.Logging
import io.ktor.client.request.*
+import io.ktor.client.request.forms.FormDataContent
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.util.*
+import kotlinx.serialization.json.Json as KotlinJson
open class ApiClient(val baseUrl: String) {
companion object {
@@ -15,24 +22,41 @@ open class ApiClient(val baseUrl: String) {
protected const val ApiAccept = "Accept"
protected const val ApiJsonMediaType = "application/json"
protected const val ApiFormDataMediaType = "multipart/form-data"
+ protected const val ApiFormURLType = "application/x-www-form-urlencoded"
protected const val ApiXmlMediaType = "application/xml"
val client: HttpClient = HttpClient(CIO) {
- install(JsonFeature)
+ install(JsonFeature) {
+ serializer = KotlinxSerializer(
+ KotlinJson {
+ ignoreUnknownKeys = true
+ }
+ )
+ }
+ install(Logging) {
+ logger = Logger.DEFAULT
+ level = LogLevel.HEADERS
+ }
}
val defaultHeaders: Map<String, String> =
mapOf(
ApiContentType to ApiJsonMediaType,
- ApiAccept to ApiJsonMediaType)
+ ApiAccept to ApiJsonMediaType
+ )
val jsonHeaders: Map<String, String> =
mapOf(
ApiContentType to ApiJsonMediaType,
- ApiAccept to ApiJsonMediaType)
+ ApiAccept to ApiJsonMediaType
+ )
}
- protected inline fun <reified T> fillRequest(requestBuilder: HttpRequestBuilder, content: T, mediaType: String = ApiJsonMediaType) {
+ protected inline fun <reified T> fillRequest(
+ requestBuilder: HttpRequestBuilder,
+ content: T,
+ mediaType: String = ApiJsonMediaType
+ ) {
when {
mediaType == ApiFormDataMediaType && content is Map<*, *> -> {
val parametersBuilder = ParametersBuilder()
@@ -51,6 +75,13 @@ open class ApiClient(val baseUrl: String) {
requestBuilder.body = content
}
}
+ mediaType == ApiFormURLType && content is Map<*, *> -> {
+ val parametersBuilder = ParametersBuilder()
+ content.forEach { item ->
+ parametersBuilder[item.key as String] = item.value as String
+ }
+ requestBuilder.body = FormDataContent(parametersBuilder.build())
+ }
mediaType == ApiXmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers
@@ -58,7 +89,10 @@ open class ApiClient(val baseUrl: String) {
}
}
- protected suspend inline fun <reified T : Any?> request(requestConfig: RequestConfig, body: Any? = null): ApiInfrastructureResponse<T?> {
+ protected suspend inline fun <reified T : Any?> request(
+ requestConfig: RequestConfig,
+ body: Any? = null
+ ): ApiInfrastructureResponse<T?> {
val httpUrl: Url
try {
httpUrl = Url(baseUrl)
@@ -67,7 +101,7 @@ open class ApiClient(val baseUrl: String) {
}
val urlBuilder = URLBuilder(httpUrl)
- .path(requestConfig.path.trimStart('/'))
+ .path("${httpUrl.encodedPath.trimStart('/')}${requestConfig.path}")
requestConfig.query.forEach { query ->
query.value.forEach { queryValue ->
@@ -76,7 +110,7 @@ open class ApiClient(val baseUrl: String) {
}
val url = urlBuilder.build()
- val headers = requestConfig.headers + defaultHeaders
+ val headers = defaultHeaders + requestConfig.headers
if (headers[ApiContentType] ?: "" == "") {
throw IllegalStateException("Missing Content-Type header. This is required.")
@@ -121,10 +155,6 @@ open class ApiClient(val baseUrl: String) {
}
}
- headers.forEach { header ->
- request.headers[header.key] = header.value
- }
-
val response: HttpResponse = client.request(request)
// TODO: handle specific mapping types. e.g. Map<int, Class<?>>
@@ -141,11 +171,13 @@ open class ApiClient(val baseUrl: String) {
in 200..299 -> return Success(
response.receive(),
response.status.value,
- response.headers.toMap())
+ response.headers.toMap()
+ )
in 400..499 -> return ClientError(
response.receive(),
response.status.value,
- response.headers.toMap())
+ response.headers.toMap()
+ )
else -> return ServerError(
null,
response.receive(),