Skip to content

Commit 7723b78

Browse files
committed
Add response models
1 parent eefa489 commit 7723b78

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2612
-814
lines changed

build.gradle

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
plugins {
2-
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
2+
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
33
id 'java-library'
44
}
55

6-
76
ext {
87
PUBLISH_GROUP_ID = 'io.appwrite'
98
PUBLISH_ARTIFACT_ID = 'sdk-for-kotlin'
@@ -27,12 +26,12 @@ repositories {
2726
}
2827

2928
dependencies {
30-
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3")
29+
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
3130
api(platform("com.squareup.okhttp3:okhttp-bom:4.9.0"))
3231
api("com.squareup.okhttp3:okhttp")
3332
implementation("com.squareup.okhttp3:okhttp-urlconnection")
3433
implementation("com.squareup.okhttp3:logging-interceptor")
35-
implementation("com.google.code.gson:gson:2.8.5")
34+
implementation("com.google.code.gson:gson:2.8.7")
3635

3736
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
3837
}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

settings.gradle

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
21
rootProject.name = 'sdk-for-kotlin'
32

src/main/kotlin/io/appwrite/Client.kt

+88-46
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package io.appwrite
22

3-
import com.google.gson.Gson
3+
import com.google.gson.GsonBuilder
4+
import com.google.gson.reflect.TypeToken
45
import io.appwrite.exceptions.AppwriteException
5-
import io.appwrite.extensions.JsonExtensions.fromJson
6-
import io.appwrite.models.Error
6+
import io.appwrite.extensions.fromJson
7+
import io.appwrite.json.PreciseNumberAdapter
78
import kotlinx.coroutines.CoroutineScope
89
import kotlinx.coroutines.Dispatchers
910
import kotlinx.coroutines.Job
@@ -15,6 +16,7 @@ import okhttp3.MediaType.Companion.toMediaType
1516
import okhttp3.RequestBody.Companion.asRequestBody
1617
import okhttp3.RequestBody.Companion.toRequestBody
1718
import okhttp3.logging.HttpLoggingInterceptor
19+
import java.io.BufferedInputStream
1820
import java.io.BufferedReader
1921
import java.io.File
2022
import java.io.IOException
@@ -38,20 +40,26 @@ class Client @JvmOverloads constructor(
3840

3941
private val job = Job()
4042

41-
private lateinit var http: OkHttpClient
43+
private val gson = GsonBuilder().registerTypeAdapter(
44+
object : TypeToken<Map<String, Any>>(){}.type,
45+
PreciseNumberAdapter()
46+
).create()
47+
48+
lateinit var http: OkHttpClient
4249

4350
private val headers: MutableMap<String, String>
44-
51+
4552
val config: MutableMap<String, String>
4653

54+
4755
init {
4856
headers = mutableMapOf(
4957
"content-type" to "application/json",
5058
"x-sdk-version" to "appwrite:kotlin:0.1.1",
5159
"x-appwrite-response-format" to "0.11.0"
5260
)
5361
config = mutableMapOf()
54-
62+
5563
setSelfSigned(selfSigned)
5664
}
5765

@@ -115,10 +123,10 @@ class Client @JvmOverloads constructor(
115123

116124
/**
117125
* Set self Signed
118-
*
126+
*
119127
* @param status
120128
*
121-
* @return this
129+
* @return this
122130
*/
123131
fun setSelfSigned(status: Boolean): Client {
124132
selfSigned = status
@@ -134,9 +142,12 @@ class Client @JvmOverloads constructor(
134142
try {
135143
// Create a trust manager that does not validate certificate chains
136144
val trustAllCerts = arrayOf<TrustManager>(
145+
@Suppress("CustomX509TrustManager")
137146
object : X509TrustManager {
147+
@Suppress("TrustAllX509TrustManager")
138148
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
139149
}
150+
@Suppress("TrustAllX509TrustManager")
140151
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
141152
}
142153
override fun getAcceptedIssuers(): Array<X509Certificate> {
@@ -175,11 +186,11 @@ class Client @JvmOverloads constructor(
175186

176187
/**
177188
* Add Header
178-
*
189+
*
179190
* @param key
180191
* @param value
181192
*
182-
* @return this
193+
* @return this
183194
*/
184195
fun addHeader(key: String, value: String): Client {
185196
headers[key] = value
@@ -188,22 +199,23 @@ class Client @JvmOverloads constructor(
188199

189200
/**
190201
* Send the HTTP request
191-
*
202+
*
192203
* @param method
193204
* @param path
194205
* @param headers
195206
* @param params
196207
*
197-
* @return [Response]
208+
* @return [Response]
198209
*/
199210
@Throws(AppwriteException::class)
200-
suspend fun call(
201-
method: String,
202-
path: String,
203-
headers: Map<String, String> = mapOf(),
204-
params: Map<String, Any?> = mapOf()
205-
): Response {
206-
211+
suspend fun <T> call(
212+
method: String,
213+
path: String,
214+
headers: Map<String, String> = mapOf(),
215+
params: Map<String, Any?> = mapOf(),
216+
responseType: Class<T>,
217+
convert: ((Map<String, Any,>) -> T)? = null
218+
): T {
207219
val filteredParams = params.filterValues { it != null }
208220

209221
val requestHeaders = this.headers.toHeaders().newBuilder()
@@ -238,7 +250,7 @@ class Client @JvmOverloads constructor(
238250
.get()
239251
.build()
240252

241-
return awaitResponse(request)
253+
return awaitResponse(request, responseType, convert)
242254
}
243255

244256
val body = if (MultipartBody.FORM.toString() == headers["content-type"]) {
@@ -266,7 +278,7 @@ class Client @JvmOverloads constructor(
266278
}
267279
builder.build()
268280
} else {
269-
Gson().toJson(filteredParams)
281+
gson.toJson(filteredParams)
270282
.toRequestBody("application/json".toMediaType())
271283
}
272284

@@ -276,21 +288,24 @@ class Client @JvmOverloads constructor(
276288
.method(method, body)
277289
.build()
278290

279-
return awaitResponse(request)
291+
return awaitResponse(request, responseType, convert)
280292
}
281293

282294
/**
283295
* Await Response
284-
*
285-
* @param method
286-
* @param path
287-
* @param headers
288-
* @param params
289296
*
290-
* @return [Response]
297+
* @param request
298+
* @param responseType
299+
* @param convert
300+
*
301+
* @return [T]
291302
*/
292303
@Throws(AppwriteException::class)
293-
private suspend fun awaitResponse(request: Request) = suspendCancellableCoroutine<Response> {
304+
private suspend fun <T> awaitResponse(
305+
request: Request,
306+
responseType: Class<T>,
307+
convert: ((Map<String, Any,>) -> T)? = null
308+
) = suspendCancellableCoroutine<T> {
294309
http.newCall(request).enqueue(object : Callback {
295310
override fun onFailure(call: Call, e: IOException) {
296311
if (it.isCancelled) {
@@ -299,27 +314,54 @@ class Client @JvmOverloads constructor(
299314
it.cancel(e)
300315
}
301316

317+
@Suppress("UNCHECKED_CAST")
302318
override fun onResponse(call: Call, response: Response) {
303-
if (response.code >= 400) {
304-
val bodyString = response.body
305-
?.charStream()
306-
?.buffered()
307-
?.use(BufferedReader::readText) ?: ""
308-
309-
val contentType: String = response.headers["content-type"] ?: ""
310-
val error = if (contentType.contains("application/json", ignoreCase = true)) {
311-
bodyString.fromJson(Error::class.java)
319+
if (!response.isSuccessful) {
320+
val body = response.body!!
321+
.charStream()
322+
.buffered()
323+
.use(BufferedReader::readText)
324+
val error = if (response.headers["content-type"]?.contains("application/json") == true) {
325+
body.fromJson()
312326
} else {
313-
Error(bodyString, response.code)
327+
AppwriteException(body, response.code)
314328
}
315-
316-
it.cancel(AppwriteException(
317-
error.message,
318-
error.code,
319-
bodyString
320-
))
329+
it.cancel(error)
330+
return
331+
}
332+
when {
333+
responseType == Boolean::class.java -> {
334+
it.resume(true as T)
335+
return
336+
}
337+
responseType == ByteArray::class.java -> {
338+
it.resume(response.body!!
339+
.byteStream()
340+
.buffered()
341+
.use(BufferedInputStream::readBytes) as T
342+
)
343+
return
344+
}
345+
response.body == null -> {
346+
it.resume(true as T)
347+
return
348+
}
349+
}
350+
val body = response.body!!
351+
.charStream()
352+
.buffered()
353+
.use(BufferedReader::readText)
354+
if (body.isEmpty()) {
355+
it.resume(true as T)
356+
return
321357
}
322-
it.resume(response)
358+
val map = gson.fromJson<Map<String, Any>>(
359+
body,
360+
object : TypeToken<Map<String, Any>>(){}.type
361+
)
362+
it.resume(
363+
convert?.invoke(map) ?: map as T
364+
)
323365
}
324366
})
325367
}

src/main/kotlin/io/appwrite/exceptions/AppwriteException.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.appwrite.exceptions
33
import java.lang.Exception
44

55
class AppwriteException(
6-
message: String? = null,
6+
override val message: String? = null,
77
val code: Int? = null,
88
val response: String? = null
99
) : Exception(message)

src/main/kotlin/io/appwrite/extensions/JsonExtensions.kt

+28-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,33 @@ package io.appwrite.extensions
22

33
import com.google.gson.Gson
44

5-
object JsonExtensions {
5+
val gson = Gson()
66

7-
fun Any.toJson(): String =
8-
Gson().toJson(this)
7+
fun Any.toJson(): String =
8+
gson.toJson(this)
99

10-
fun <T> String.fromJson(clazz: Class<T>): T =
11-
Gson().fromJson(this, clazz)
12-
}
10+
fun <T> String.fromJson(clazz: Class<T>): T =
11+
gson.fromJson(this, clazz)
12+
13+
inline fun <reified T> String.fromJson(): T =
14+
gson.fromJson(this, T::class.java)
15+
16+
fun <T> Any.jsonCast(to: Class<T>): T =
17+
toJson().fromJson(to)
18+
19+
inline fun <reified T> Any.jsonCast(): T =
20+
toJson().fromJson(T::class.java)
21+
22+
fun <T> Any.tryJsonCast(to: Class<T>): T? = try {
23+
toJson().fromJson(to)
24+
} catch (ex: Exception) {
25+
ex.printStackTrace()
26+
null
27+
}
28+
29+
inline fun <reified T> Any.tryJsonCast(): T? = try {
30+
toJson().fromJson(T::class.java)
31+
} catch (ex: Exception) {
32+
ex.printStackTrace()
33+
null
34+
}

0 commit comments

Comments
 (0)