Kotlin API Integration
Calling the SnapIt REST API directly in Jetpack Compose using native Coroutines and OkHttp.
If you prefer not to include the binary size of the native SDK, you can issue direct API POST requests to our servers from Compose views:
ComposeView.kt
package com.example.vton
import android.os.Bundle
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONArray
import org.json.JSONObject
// 1. Direct API Service Layer
class VTONService {
private val client = OkHttpClient()
private val mediaType = "application/json; charset=utf-8".toMediaType()
suspend fun generateTryOn(garmentUrl: String): String = withContext(Dispatchers.IO) {
val url = "https://apisdk.snapmydesign.com/api/v1/vton/generate"
// Prepare JSON payload
val jsonPayload = JSONObject().apply {
put("model_name", "medium")
put("inputClothesImageUrls", JSONArray().apply { put(garmentUrl) })
}
val body = jsonPayload.toString().toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.post(body)
.addHeader("X-API-Key", "smd_live_your_api_key_here")
.addHeader("Content-Type", "application/json")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw Exception("HTTP Error: ${response.code}")
val responseBody = response.body?.string() ?: throw Exception("Empty response body")
val jsonResponse = JSONObject(responseBody)
if (jsonResponse.optString("status") == "success" || jsonResponse.has("outputImageUrl")) {
jsonResponse.getString("outputImageUrl")
} else {
throw Exception(jsonResponse.optString("message", "Generation failed"))
}
}
}
}
// 2. Jetpack Compose Screen View
@Composable
fun ProductDetailScreen(service: VTONService = VTONService()) {
var resultUrl by remember { mutableStateOf<String?>(null) }
var isLoading by remember { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) }
val coroutineScope = rememberCoroutineScope()
val garmentUrl = "https://assets.url/dress.jpg"
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("SnapIt Direct API Integration", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(24.dp))
if (isLoading) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(8.dp))
Text("AI workers processing image...")
} else if (resultUrl != null) {
// Coil's AsyncImage for rendering try-on result
AsyncImage(
model = resultUrl,
contentDescription = "Try-On Result",
modifier = Modifier
.fillMaxWidth()
.height(350.dp)
)
} else {
Text("Ready to run virtual try-on.", color = MaterialTheme.colorScheme.outline)
}
errorMessage?.let {
Spacer(modifier = Modifier.height(8.dp))
Text("Error: $it", color = MaterialTheme.colorScheme.error)
}
Spacer(modifier = Modifier.height(24.dp))
Button(
onClick = {
isLoading = true
errorMessage = null
coroutineScope.launch {
try {
val output = service.generateTryOn(garmentUrl)
resultUrl = output
} catch (e: Exception) {
errorMessage = e.message ?: "Unknown error"
} finally {
isLoading = false
}
}
},
enabled = !isLoading,
modifier = Modifier.fillMaxWidth()
) {
Text("Generate Try-On")
}
}
}