Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Changed

- URL validation is stricter in the connection screen and URI protocol handler
- the http client has relaxed syntax rules when deserializing JSON responses

## 0.6.0 - 2025-07-25

Expand Down
12 changes: 9 additions & 3 deletions src/main/kotlin/com/coder/toolbox/sdk/CoderRestClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.coder.toolbox.sdk
import com.coder.toolbox.CoderToolboxContext
import com.coder.toolbox.sdk.convertors.ArchConverter
import com.coder.toolbox.sdk.convertors.InstantConverter
import com.coder.toolbox.sdk.convertors.LoggingConverterFactory
import com.coder.toolbox.sdk.convertors.OSConverter
import com.coder.toolbox.sdk.convertors.UUIDConverter
import com.coder.toolbox.sdk.ex.APIResponseException
Expand Down Expand Up @@ -74,10 +75,10 @@ open class CoderRestClient(
var builder = OkHttpClient.Builder()

if (context.proxySettings.getProxy() != null) {
context.logger.debug("proxy: ${context.proxySettings.getProxy()}")
context.logger.info("proxy: ${context.proxySettings.getProxy()}")
builder.proxy(context.proxySettings.getProxy())
} else if (context.proxySettings.getProxySelector() != null) {
context.logger.debug("proxy selector: ${context.proxySettings.getProxySelector()}")
context.logger.info("proxy selector: ${context.proxySettings.getProxySelector()}")
builder.proxySelector(context.proxySettings.getProxySelector()!!)
}

Expand Down Expand Up @@ -133,7 +134,12 @@ open class CoderRestClient(

retroRestClient =
Retrofit.Builder().baseUrl(url.toString()).client(httpClient)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addConverterFactory(
LoggingConverterFactory.wrap(
context,
MoshiConverterFactory.create(moshi).asLenient()
)
)
.build().create(CoderV2RestFacade::class.java)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.coder.toolbox.sdk.convertors

import com.coder.toolbox.CoderToolboxContext
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type

class LoggingConverterFactory private constructor(
private val context: CoderToolboxContext,
private val delegate: Converter.Factory,
) : Converter.Factory() {

override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
// Get the delegate converter
val delegateConverter = delegate.responseBodyConverter(type, annotations, retrofit)
?: return null

@Suppress("UNCHECKED_CAST")
return LoggingMoshiConverter(context, delegateConverter as Converter<ResponseBody, Any?>)
}

override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit
): Converter<*, RequestBody>? {
return delegate.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit)
}

override fun stringConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<*, String>? {
return delegate.stringConverter(type, annotations, retrofit)
}

companion object {
fun wrap(
context: CoderToolboxContext,
delegate: Converter.Factory,
): LoggingConverterFactory {
return LoggingConverterFactory(context, delegate)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.coder.toolbox.sdk.convertors

import com.coder.toolbox.CoderToolboxContext
import okhttp3.ResponseBody
import okhttp3.ResponseBody.Companion.toResponseBody
import retrofit2.Converter

class LoggingMoshiConverter(
private val context: CoderToolboxContext,
private val delegate: Converter<ResponseBody, Any?>
) : Converter<ResponseBody, Any> {

override fun convert(value: ResponseBody): Any? {
val bodyString = value.string()

return try {
// Parse with Moshi
delegate.convert(bodyString.toResponseBody(value.contentType()))
} catch (e: Exception) {
// Log the raw content that failed to parse
context.logger.error(
"""
|Moshi parsing failed:
|Content-Type: ${value.contentType()}
|Content: $bodyString
|Error: ${e.message}
""".trimMargin()
)

// Re-throw so the onFailure callback still gets called
throw e
}
}
}
Loading