relatively new to Kotlin and wanted to get some practice in. I am trying to create a simple command-line project that consumes the CoinbaseAPI. I want to be able to input a Currency Code, i.e. USD, EUR and once a user inputs the currency, I want to query the Coinbase public API using that currency.
Here’s what I have so far
main.kt
@Serializable
@OptIn(kotlinx.serialization.ExperimentalSerializationApi::class)
data class ExchangeRates(val data: Map<String, Double>)
@Serializable
@OptIn(kotlinx.serialization.ExperimentalSerializationApi::class)
data class BinanceTicker(val symbol: String, val priceChangePercent: String)
@OptIn(kotlinx.serialization.ExperimentalSerializationApi::class)
fun main() {
val scanner = Scanner(System.`in`)
print("Enter an ISO-4217 currency code (e.g., USD, EUR): ")
val currencyCode = scanner.next()
val client = OkHttpClient()
// Query Coinbase Public API
val coinbaseApiUrl = "https://api.coinbase.com/v2/exchange-rates?currency=$currencyCode"
val coinbaseRequest = Request.Builder().url(coinbaseApiUrl).build()
val coinbaseResponse: Response = client.newCall(coinbaseRequest).execute()
val coinbaseResponseBody = coinbaseResponse.body?.string()
val exchangeRates = Json.decodeFromString<ExchangeRates>(coinbaseResponseBody.orEmpty())
val cryptoCurrencies = filterCryptoCurrencies(exchangeRates.data.keys)
// Query Binance 24-Hour Ticker API
val binanceApiUrl = "https://api.binance.us/api/v3/ticker/24hr"
val binanceRequest = Request.Builder().url(binanceApiUrl).build()
val binanceResponse: Response = client.newCall(binanceRequest).execute()
val binanceResponseBody = binanceResponse.body?.string()
val binanceTickers = Json.decodeFromString<List<BinanceTicker>>(binanceResponseBody.orEmpty())
val results = calculateAndOutputResults(cryptoCurrencies, binanceTickers, exchangeRates)
results.forEach { (cryptoCode, value, percentChange) ->
println("Crypto: $cryptoCode, Value: $value, Percent Change: $percentChange%")
}
}
fun filterCryptoCurrencies(allCurrencies: Set<String>): List<String> {
// Filtering out non-cryptocurrencies based on a provided list
val cryptoCurrenciesList = listOf("BTC", "ETH", "ADA", "SOL") // Example list
return allCurrencies.filter { it in cryptoCurrenciesList }
}
fun calculateAndOutputResults(
cryptoCurrencies: List<String>,
binanceTickers: List<BinanceTicker>,
exchangeRates: ExchangeRates
): List<Triple<String, Double, String>> {
return cryptoCurrencies.mapNotNull { cryptoCode ->
binanceTickers.find { it.symbol.startsWith("${cryptoCode}BTC") }?.let { binanceTicker ->
val percentChange = binanceTicker.priceChangePercent
val value = exchangeRates.data[cryptoCode]
if (value != null) {
Triple(cryptoCode, value, percentChange)
} else {
null
}
}
}
}
When I run this program, I am able to input a Currency Code but once I hit enter, I get this error
Exception in thread "main" kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 25: Failed to parse type 'double' for input 'USD'
JSON input: {"data":{"currency":"USD","rates":{"00":"14.69507714915.....
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24)
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32)
at kotlinx.serialization.json.internal.JsonLexer.fail(JsonLexer.kt:493)
at kotlinx.serialization.json.internal.JsonLexer.fail$default(JsonLexer.kt:492)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeDouble(StreamingJsonDecoder.kt:299)
at kotlinx.serialization.internal.DoubleSerializer.deserialize(Primitives.kt:128)
at kotlinx.serialization.internal.DoubleSerializer.deserialize(Primitives.kt:124)
at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:63)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:32)
at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:535)
at kotlinx.serialization.internal.MapLikeSerializer.readElement(CollectionSerializers.kt:111)
at kotlinx.serialization.internal.MapLikeSerializer.readElement(CollectionSerializers.kt:84)
at kotlinx.serialization.internal.AbstractCollectionSerializer.readElement$default(CollectionSerializers.kt:51)
at kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:36)
at kotlinx.serialization.internal.AbstractCollectionSerializer.deserialize(CollectionSerializers.kt:43)
at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:63)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:32)
at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
at ExchangeRates$$serializer.deserialize(Main.kt:9)
at ExchangeRates$$serializer.deserialize(Main.kt:9)
at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:63)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:32)
at kotlinx.serialization.json.Json.decodeFromString(Json.kt:100)
at MainKt.main(Main.kt:73)
at MainKt.main(Main.kt)
I’m not sure how to proceed, any help is much appreciated.