Ktor HTTP client implementation for JavaScript platform providing asynchronous HTTP client functionality specifically tailored for JavaScript environments.
—
JavaScript-specific error handling with wrapped native JavaScript errors for debugging and error reporting. The Ktor Client JS provides specialized error classes to handle JavaScript runtime errors consistently across different platforms.
Wrapper class for JavaScript error objects that provides consistent error handling across browser and Node.js environments.
/**
* Wrapper for javascript error objects.
*
* @property origin The original JavaScript error object
*/
class JsError(val origin: dynamic) : Throwable("Error from javascript[$origin].")Usage Examples:
import io.ktor.client.*
import io.ktor.client.engine.js.*
import io.ktor.client.request.*
val client = HttpClient(Js)
try {
val response = client.get("https://invalid-url")
} catch (error: JsError) {
// Access the original JavaScript error
println("JavaScript error: ${error.origin}")
// The error message includes the original error
println("Error message: ${error.message}")
// Can inspect JavaScript error properties
val jsError = error.origin
console.log("Original JS error:", jsError)
}For WebAssembly-JavaScript environments, a specialized variant provides type-safe error handling.
/**
* WASM-JS specific wrapper for JavaScript error objects.
*
* @property origin The original JavaScript error object as JsAny
*/
class JsError(val origin: JsAny) : Throwable("Error from javascript[$origin].")import io.ktor.client.*
import io.ktor.client.engine.js.*
import io.ktor.client.request.*
val client = HttpClient(Js)
try {
val response = client.get("https://unreachable-server.com")
} catch (error: JsError) {
// Network-related JavaScript errors
when {
error.message?.contains("TypeError") == true -> {
println("Network error: ${error.origin}")
}
error.message?.contains("Failed to fetch") == true -> {
println("Fetch failed: ${error.origin}")
}
else -> {
println("Unknown network error: ${error.origin}")
}
}
}try {
val response = client.get("https://cors-restricted-api.com") {
fetchOptions {
mode = "cors"
}
}
} catch (error: JsError) {
// CORS-related errors are wrapped as JsError
println("CORS error occurred: ${error.origin}")
// Original error might contain CORS-specific information
val corsError = error.origin
console.log("CORS details:", corsError)
}import org.w3c.dom.AbortController
val controller = AbortController()
try {
val response = client.get("https://slow-api.com") {
fetchOptions {
signal = controller.signal
}
}
} catch (error: JsError) {
// Check if error is due to request cancellation
val jsError = error.origin
if (jsError.name == "AbortError") {
println("Request was cancelled")
} else {
println("Other error: ${error.origin}")
}
}
// Cancel the request
controller.abort()import io.ktor.client.plugins.*
val client = HttpClient(Js) {
install(HttpTimeout) {
requestTimeoutMillis = 5000
}
}
try {
val response = client.get("https://very-slow-api.com")
} catch (timeout: HttpRequestTimeoutException) {
// Ktor timeout exception
println("Request timed out: ${timeout.message}")
} catch (error: JsError) {
// JavaScript timeout or other errors
println("JavaScript error: ${error.origin}")
}fun inspectJsError(error: JsError) {
val jsError = error.origin
// Common JavaScript error properties
val name = jsError.name as? String
val message = jsError.message as? String
val stack = jsError.stack as? String
println("Error name: $name")
println("Error message: $message")
println("Error stack: $stack")
// Platform-specific properties
when {
name == "TypeError" -> println("Type error occurred")
name == "NetworkError" -> println("Network issue detected")
name == "AbortError" -> println("Request was aborted")
name == "TimeoutError" -> println("Request timed out")
}
}
// Usage
try {
client.get("https://problematic-url.com")
} catch (error: JsError) {
inspectJsError(error)
}import io.ktor.client.plugins.logging.*
val client = HttpClient(Js) {
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.INFO
}
}
// Custom error logging
suspend fun safeRequest(url: String): String? {
return try {
val response = client.get(url)
response.bodyAsText()
} catch (error: JsError) {
// Log the JavaScript error details
console.error("JavaScript error in request to $url:", error.origin)
// Return null or throw custom exception
null
}
}import kotlinx.coroutines.delay
import kotlin.random.Random
suspend fun requestWithRetry(
url: String,
maxRetries: Int = 3,
baseDelayMs: Long = 1000
): HttpResponse? {
var attempt = 0
while (attempt < maxRetries) {
try {
return client.get(url)
} catch (error: JsError) {
attempt++
if (attempt >= maxRetries) {
println("Max retries exceeded for $url")
throw error
}
// Exponential backoff with jitter
val delayMs = baseDelayMs * (1L shl attempt) + Random.nextLong(1000)
println("Request failed, retrying in ${delayMs}ms (attempt $attempt)")
delay(delayMs)
}
}
return null
}suspend fun requestWithFallback(primaryUrl: String, fallbackUrl: String): HttpResponse {
return try {
client.get(primaryUrl)
} catch (primaryError: JsError) {
println("Primary request failed: ${primaryError.origin}")
try {
client.get(fallbackUrl)
} catch (fallbackError: JsError) {
println("Fallback request also failed: ${fallbackError.origin}")
throw fallbackError
}
}
}
// Usage
val response = requestWithFallback(
"https://primary-api.com/data",
"https://backup-api.com/data"
)fun handleBrowserErrors(error: JsError) {
val jsError = error.origin
when (jsError.name) {
"SecurityError" -> {
println("Security policy violation (CORS, mixed content, etc.)")
}
"NetworkError" -> {
println("Network connectivity issue")
}
"QuotaExceededError" -> {
println("Storage quota exceeded")
}
else -> {
println("Other browser error: ${jsError.name}")
}
}
}fun handleNodeErrors(error: JsError) {
val jsError = error.origin
val code = jsError.code as? String
when (code) {
"ENOTFOUND" -> {
println("DNS resolution failed")
}
"ECONNREFUSED" -> {
println("Connection refused by server")
}
"ETIMEDOUT" -> {
println("Connection timed out")
}
"ECONNRESET" -> {
println("Connection reset by peer")
}
else -> {
println("Node.js error: $code - ${jsError.message}")
}
}
}fun handleUniversalError(error: JsError) {
val jsError = error.origin
val name = jsError.name as? String
val message = jsError.message as? String
// Log all error details
console.log("Full error object:", jsError)
// Handle common patterns
when {
name == "AbortError" -> println("Request was cancelled")
message?.contains("Failed to fetch") == true -> println("Network request failed")
message?.contains("CORS") == true -> println("CORS policy violation")
name == "TypeError" && message?.contains("NetworkError") == true -> {
println("Network error (possibly offline)")
}
else -> {
println("Unhandled JavaScript error: $name - $message")
}
}
}Always Wrap HTTP Calls: Use try-catch blocks around HTTP requests to handle JsError exceptions
Inspect Original Errors: Access the origin property to get detailed JavaScript error information
Platform Detection: Handle browser vs Node.js specific error patterns differently
Error Logging: Log JavaScript errors to external services for debugging production issues
Graceful Degradation: Implement fallback mechanisms for network failures
User-Friendly Messages: Convert technical JavaScript errors into user-understandable messages
Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-js