diff options
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.kt | 58 |
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(), |