1
1
package { {packageName} }.infrastructure
2
2
3
+
3
4
import io.ktor.client.HttpClient
4
5
import io.ktor.client.HttpClientConfig
5
6
import io.ktor.client.engine.HttpClientEngine
6
- import io.ktor.client.features.json.JsonFeature
7
- import io.ktor.client.features.json.JsonSerializer
8
- import io.ktor.client.request.*
7
+ import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
9
8
import io.ktor.client.request.forms.FormDataContent
10
9
import io.ktor.client.request.forms.MultiPartFormDataContent
11
10
import io.ktor.client.request.header
12
11
import io.ktor.client.request.parameter
12
+ import io.ktor.client.request.request
13
+ import io.ktor.client.request.setBody
13
14
import io.ktor.client.statement.HttpResponse
14
- import io.ktor.client.utils.EmptyContent
15
- import io.ktor.http.*
16
- import io.ktor.http.content.ByteArrayContent
17
- import io.ktor.http.content.OutgoingContent
15
+ import io.ktor.http.HttpHeaders
16
+ import io.ktor.http.HttpMethod
17
+ import io.ktor.http.Parameters
18
+ import io.ktor.http.URLBuilder
18
19
import io.ktor.http.content.PartData
19
- import kotlin.Unit
20
-
20
+ import io.ktor.http.encodeURLQueryComponent
21
+ import io.ktor.http.encodedPath
22
+ import io.ktor.http.takeFrom
21
23
{ {#gson} }
22
- import com.google.gson.Gson
23
- import java.nio.charset.StandardCharsets
24
+ import io.ktor.serialization.gson.*
25
+ import com.google.gson.GsonBuilder
26
+ import java.text.DateFormat
24
27
{ {/gson} }
25
28
{ {#jackson} }
29
+ import io.ktor.serialization.jackson.*
30
+ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
26
31
import com.fasterxml.jackson.databind.ObjectMapper
32
+ import com.fasterxml.jackson.databind.SerializationFeature
33
+ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
34
+ import com.fasterxml.jackson.core.util.DefaultIndenter
35
+ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
27
36
{ {/jackson} }
28
-
37
+ import org.openapitools.client.auth.ApiKeyAuth
38
+ import org.openapitools.client.auth.Authentication
39
+ import org.openapitools.client.auth.HttpBasicAuth
40
+ import org.openapitools.client.auth.HttpBearerAuth
41
+ import org.openapitools.client.auth.OAuth
29
42
import { {packageName} }.auth.*
30
43
31
44
{ {#nonPublicApi} }internal { {/nonPublicApi} }open class ApiClient(
32
45
private val baseUrl: String,
33
46
httpClientEngine: HttpClientEngine?,
34
47
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
35
- json: { {#gson} }Gson{ {/gson} }{ {#jackson} }ObjectMapper{ {/jackson} },
48
+ { {#gson} }
49
+ jsonBlock: GsonBuilder.() -> Unit = JSON_DEFAULT,
50
+ { {/gson} }
51
+ { {#jackson} }
52
+ jsonBlock: ObjectMapper.() -> Unit = JSON_DEFAULT,
53
+ { {/jackson} }
36
54
) {
37
55
38
- private val serializer: JsonSerializer by lazy {
39
- JsonSerializerImpl(json)
40
- }
41
-
42
56
private val clientConfig: (HttpClientConfig< *> ) -> Unit by lazy {
43
57
{
44
- // Hold a reference to the serializer to avoid freezing the entire ApiClient instance
45
- // when the JsonFeature is configured.
46
- val serializerReference = serializer
47
- it.install(JsonFeature) { serializer = serializerReference }
58
+ it.install(ContentNegotiation) {
59
+ {{#gson} }
60
+ gson { jsonBlock() }
61
+ { {/gson} }
62
+ { {#jackson} }
63
+ jackson { jsonBlock() }
64
+ { {/jackson} }
65
+ }
48
66
httpClientConfig?.invoke(it)
49
67
}
50
68
}
@@ -67,9 +85,24 @@ import {{packageName}}.auth.*
67
85
{ {/hasAuthMethods} }
68
86
69
87
{ {#nonPublicApi} }internal { {/nonPublicApi} }companion object {
70
- const val BASE_URL = " {{{basePath}}}"
71
- val JSON_DEFAULT = {{#gson} }Gson(){ {/gson} }{ {#jackson} }ObjectMapper(){ {/jackson} }
72
- protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
88
+ const val BASE_URL = " {{{basePath}}}"
89
+ {{#gson} }
90
+ val JSON_DEFAULT : GsonBuilder.() -> Unit = {
91
+ setDateFormat(DateFormat.LONG)
92
+ setPrettyPrinting()
93
+ }
94
+ { {/gson} }
95
+ { {#jackson} }
96
+ val JSON_DEFAULT: ObjectMapper.() -> Unit = {
97
+ configure(SerializationFeature.INDENT_OUTPUT, true )
98
+ setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
99
+ indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
100
+ indentObjectsWith(DefaultIndenter(" " , " \n " ))
101
+ } )
102
+ registerModule(JavaTimeModule())
103
+ }
104
+ { {/jackson} }
105
+ protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
73
106
}
74
107
75
108
/**
@@ -78,7 +111,7 @@ import {{packageName}}.auth.*
78
111
* @param username Username
79
112
*/
80
113
fun setUsername(username: String) {
81
- val auth = authentications? .values? .firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
114
+ val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
82
115
?: throw Exception("No HTTP basic authentication configured")
83
116
auth.username = username
84
117
}
@@ -89,7 +122,7 @@ import {{packageName}}.auth.*
89
122
* @param password Password
90
123
*/
91
124
fun setPassword(password: String) {
92
- val auth = authentications? .values? .firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
125
+ val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
93
126
?: throw Exception("No HTTP basic authentication configured")
94
127
auth.password = password
95
128
}
@@ -101,7 +134,7 @@ import {{packageName}}.auth.*
101
134
* @param paramName The name of the API key parameter, or null or set the first key.
102
135
*/
103
136
fun setApiKey(apiKey: String, paramName: String? = null) {
104
- val auth = authentications? .values? .firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
137
+ val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
105
138
?: throw Exception("No API key authentication configured")
106
139
auth.apiKey = apiKey
107
140
}
@@ -113,7 +146,7 @@ import {{packageName}}.auth.*
113
146
* @param paramName The name of the API key parameter, or null or set the first key.
114
147
*/
115
148
fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
116
- val auth = authentications? .values? .firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
149
+ val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
117
150
?: throw Exception("No API key authentication configured")
118
151
auth.apiKeyPrefix = apiKeyPrefix
119
152
}
@@ -124,7 +157,7 @@ import {{packageName}}.auth.*
124
157
* @param accessToken Access token
125
158
*/
126
159
fun setAccessToken(accessToken: String) {
127
- val auth = authentications? .values? .firstOrNull { it is OAuth } as OAuth?
160
+ val auth = authentications.values.firstOrNull { it is OAuth } as OAuth?
128
161
?: throw Exception("No OAuth2 authentication configured")
129
162
auth.accessToken = accessToken
130
163
}
@@ -135,7 +168,7 @@ import {{packageName}}.auth.*
135
168
* @param bearerToken The bearer token.
136
169
*/
137
170
fun setBearerToken(bearerToken: String) {
138
- val auth = authentications? .values? .firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
171
+ val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
139
172
?: throw Exception("No Bearer authentication configured")
140
173
auth.bearerToken = bearerToken
141
174
}
@@ -148,18 +181,13 @@ import {{packageName}}.auth.*
148
181
return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
149
182
}
150
183
151
- protected suspend fun <T: Any? > jsonRequest(requestConfig: RequestConfig<T >, body: Any? = null, authNames: kotlin.collections.List<String >): HttpResponse {
152
- val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
153
- ?: ContentType.Application.Json)
154
- return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
155
- else request(requestConfig, authNames = authNames)
156
- }
184
+ protected suspend fun <T: Any? > jsonRequest(requestConfig: RequestConfig<T >, body: Any? = null, authNames: kotlin.collections.List<String >): HttpResponse = request(requestConfig, body, authNames)
157
185
158
- protected suspend fun <T: Any? > request(requestConfig: RequestConfig<T >, body: OutgoingContent = EmptyContent , authNames: kotlin.collections.List<String >): HttpResponse {
186
+ protected suspend fun <T: Any? > request(requestConfig: RequestConfig<T >, body: Any? = null , authNames: kotlin.collections.List<String >): HttpResponse {
159
187
requestConfig.updateForAuth< T> (authNames)
160
188
val headers = requestConfig.headers
161
189
162
- return client.request< HttpResponse > {
190
+ return client.request {
163
191
this.url {
164
192
this.takeFrom(URLBuilder(baseUrl))
165
193
appendPath(requestConfig.path.trimStart(' /' ).split(' /' ))
@@ -172,8 +200,7 @@ import {{packageName}}.auth.*
172
200
this.method = requestConfig.method.httpMethod
173
201
headers.filter { header -> ! UNSAFE_HEADERS.contains(header.key) } .forEach { header -> this.header(header.key, header.value) }
174
202
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
175
- this.body = body
176
-
203
+ setBody(body)
177
204
}
178
205
}
179
206
@@ -199,13 +226,3 @@ import {{packageName}}.auth.*
199
226
RequestMethod.OPTIONS -> HttpMethod.Options
200
227
}
201
228
}
202
-
203
- { {#gson} }private class JsonSerializerImpl(private val gson: Gson) : JsonSerializer {
204
- override fun write(data: Any, contentType: ContentType): OutgoingContent =
205
- ByteArrayContent(gson.toJson(data).toByteArray(StandardCharsets.UTF_8), contentType)
206
- } { {/gson} }
207
-
208
- { {#jackson} }private class JsonSerializerImpl(private val objectMapper: ObjectMapper) : JsonSerializer {
209
- override fun write(data: Any, contentType: ContentType): OutgoingContent =
210
- ByteArrayContent(objectMapper.writeValueAsBytes(data), contentType)
211
- } { {/jackson} }
0 commit comments