Quick Start Examples
Kotlin Examples
Code examples for integrating with the API using Kotlin
This page provides practical code examples for integrating with the API using Kotlin.
Basic Client
import kotlinx.coroutines.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import java.net.HttpURLConnection
import java.net.URL
import java.io.OutputStreamWriter
@Serializable
data class IPOResponse(
val meta: Meta,
val ipos: List<IPO>
)
@Serializable
data class Meta(
val count: Int,
val countOnPage: Int,
val totalPages: Int,
val page: Int,
val limit: Int
)
@Serializable
data class IPO(
val id: String,
val name: String,
val symbol: String,
val slug: String,
val type: String? = null,
val startDate: String? = null,
val endDate: String? = null,
val listingDate: String? = null,
val priceRange: String? = null,
val listingGain: String? = null,
val status: String? = null,
val issueSize: String? = null,
val minQty: Int? = null,
val minAmount: Int? = null,
val logo: String? = null,
val about: String? = null,
val strengths: List<String>? = null,
val risks: List<String>? = null,
val schedule: List<ScheduleItem>? = null
)
@Serializable
data class ScheduleItem(
val event: String,
val date: String
)
@Serializable
data class IPODetailResponse(
val ipo: IPO
)
class IPOAlertsClient(private val apiKey: String) {
private val baseURL = "https://api.ipoalerts.in"
private val json = Json { ignoreUnknownKeys = true }
suspend fun getIPOs(
status: String? = null,
type: String? = null,
page: Int = 1,
limit: Int = 10
): IPOResponse {
val params = mutableListOf<String>()
status?.let { params.add("status=$it") }
type?.let { params.add("type=$it") }
params.add("page=$page")
params.add("limit=$limit")
val endpoint = "/ipos?${params.joinToString("&")}"
return makeRequest<IPOResponse>(endpoint)
}
suspend fun getIPO(identifier: String): IPO {
val response = makeRequest<IPODetailResponse>("/ipos/$identifier")
return response.ipo
}
private suspend fun makeRequest<T>(endpoint: String): T {
return withContext(Dispatchers.IO) {
val url = URL("$baseURL$endpoint")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.setRequestProperty("x-api-key", apiKey)
connection.setRequestProperty("Content-Type", "application/json")
if (connection.responseCode >= 400) {
throw Exception("HTTP error: ${connection.responseCode}")
}
val response = connection.inputStream.bufferedReader().readText()
json.decodeFromString<T>(response)
}
}
}
// Usage
fun main() = runBlocking {
val client = IPOAlertsClient("YOUR_API_KEY")
try {
// Get upcoming IPOs
val ipos = client.getIPOs(status = "upcoming", type = "EQ", page = 1, limit = 10)
println("Found ${ipos.meta.count} upcoming equity IPOs")
ipos.ipos.forEach { ipo ->
println("${ipo.name} (${ipo.symbol}) - ${ipo.priceRange}")
}
// Get specific IPO
val ipoDetails = client.getIPO("example-company-limited")
println("IPO Details: ${ipoDetails.name}")
} catch (e: Exception) {
println("Error: ${e.message}")
}
}
Advanced Client with Caching and Rate Limiting
import kotlinx.coroutines.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import kotlin.time.Duration.Companion.minutes
import kotlin.time.TimeSource
class AdvancedIPOAlertsClient(
private val apiKey: String,
private val requestsPerMinute: Int = 6
) {
private val baseURL = "https://api.ipoalerts.in"
private val json = Json { ignoreUnknownKeys = true }
private val cache = ConcurrentHashMap<String, CacheEntry>()
private val requestTimes = mutableListOf<Long>()
private val requestMutex = Mutex()
private val cacheTTL = 5.minutes
data class CacheEntry(
val data: Any,
val timestamp: Long
)
suspend fun getIPOsWithCache(
status: String? = null,
type: String? = null,
page: Int = 1,
limit: Int = 10
): IPOResponse {
val cacheKey = "ipos_${status}_${type}_${page}_${limit}"
val cached = getFromCache<IPOResponse>(cacheKey)
if (cached != null) {
println("Returning cached data")
return cached
}
enforceRateLimit()
val result = getIPOs(status, type, page, limit)
setCache(cacheKey, result)
return result
}
suspend fun getIPOWithCache(identifier: String): IPO {
val cacheKey = "ipo_$identifier"
val cached = getFromCache<IPODetailResponse>(cacheKey)
if (cached != null) {
println("Returning cached IPO data")
return cached.ipo
}
enforceRateLimit()
val result = getIPO(identifier)
setCache(cacheKey, IPODetailResponse(result))
return result
}
private suspend fun getIPOs(
status: String? = null,
type: String? = null,
page: Int = 1,
limit: Int = 10
): IPOResponse {
val params = mutableListOf<String>()
status?.let { params.add("status=$it") }
type?.let { params.add("type=$it") }
params.add("page=$page")
params.add("limit=$limit")
val endpoint = "/ipos?${params.joinToString("&")}"
return makeRequest<IPOResponse>(endpoint)
}
private suspend fun getIPO(identifier: String): IPO {
val response = makeRequest<IPODetailResponse>("/ipos/$identifier")
return response.ipo
}
private suspend fun enforceRateLimit() {
requestMutex.lock()
try {
val now = System.currentTimeMillis()
requestTimes.removeAll { now - it > 60000 } // Remove requests older than 1 minute
if (requestTimes.size >= requestsPerMinute) {
val sleepTime = 60000 - (now - requestTimes.first())
if (sleepTime > 0) {
delay(sleepTime)
}
}
requestTimes.add(now)
} finally {
requestMutex.unlock()
}
}
private fun <T> getFromCache(key: String): T? {
val entry = cache[key] ?: return null
val now = System.currentTimeMillis()
if (now - entry.timestamp > cacheTTL.inWholeMilliseconds) {
cache.remove(key)
return null
}
@Suppress("UNCHECKED_CAST")
return entry.data as T
}
private fun setCache(key: String, data: Any) {
cache[key] = CacheEntry(data, System.currentTimeMillis())
}
fun clearCache() {
cache.clear()
}
fun getCacheStats(): Map<String, Any> {
return mapOf(
"cacheSize" to cache.size,
"requestCount" to requestTimes.size
)
}
private suspend fun makeRequest<T>(endpoint: String): T {
return withContext(Dispatchers.IO) {
val url = URL("$baseURL$endpoint")
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.setRequestProperty("x-api-key", apiKey)
connection.setRequestProperty("Content-Type", "application/json")
if (connection.responseCode >= 400) {
throw Exception("HTTP error: ${connection.responseCode}")
}
val response = connection.inputStream.bufferedReader().readText()
json.decodeFromString<T>(response)
}
}
}
// Usage
fun main() = runBlocking {
val client = AdvancedIPOAlertsClient("YOUR_API_KEY")
try {
// First request - will be cached
val ipos1 = client.getIPOsWithCache(status = "upcoming", type = "EQ")
// Second request - will return cached data
val ipos2 = client.getIPOsWithCache(status = "upcoming", type = "EQ")
println("Found ${ipos1.meta.count} upcoming equity IPOs")
println("Cached result: ${ipos2.meta.count} upcoming equity IPOs")
println("Cache stats: ${client.getCacheStats()}")
} catch (e: Exception) {
println("Error: ${e.message}")
}
}
Android Integration with Retrofit
// build.gradle (Module: app)
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
}
// IPOAlertsApi.kt
import retrofit2.http.*
import retrofit2.Response
interface IPOAlertsApi {
@GET("ipos")
suspend fun getIPOs(
@Query("status") status: String? = null,
@Query("type") type: String? = null,
@Query("page") page: Int = 1,
@Query("limit") limit: Int = 10
): Response<IPOResponse>
@GET("ipos/{identifier}")
suspend fun getIPO(@Path("identifier") identifier: String): Response<IPODetailResponse>
}
// IPOAlertsService.kt
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
class IPOAlertsService(private val apiKey: String) {
private val api: IPOAlertsApi
init {
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val authInterceptor = Interceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("x-api-key", apiKey)
.addHeader("Content-Type", "application/json")
.build()
chain.proceed(request)
}
val client = OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.addInterceptor(loggingInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.ipoalerts.in/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
api = retrofit.create(IPOAlertsApi::class.java)
}
suspend fun getIPOs(
status: String? = null,
type: String? = null,
page: Int = 1,
limit: Int = 10
): Result<IPOResponse> {
return try {
val response = api.getIPOs(status, type, page, limit)
if (response.isSuccessful) {
Result.success(response.body()!!)
} else {
Result.failure(Exception("HTTP error: ${response.code()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
suspend fun getIPO(identifier: String): Result<IPO> {
return try {
val response = api.getIPO(identifier)
if (response.isSuccessful) {
Result.success(response.body()!!.ipo)
} else {
Result.failure(Exception("HTTP error: ${response.code()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
// IPOViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class IPOViewModel : ViewModel() {
private val service = IPOAlertsService("YOUR_API_KEY")
private val _ipos = MutableStateFlow<List<IPO>>(emptyList())
val ipos: StateFlow<List<IPO>> = _ipos.asStateFlow()
private val _loading = MutableStateFlow(false)
val loading: StateFlow<Boolean> = _loading.asStateFlow()
private val _error = MutableStateFlow<String?>(null)
val error: StateFlow<String?> = _error.asStateFlow()
fun loadIPOs(status: String? = null, type: String? = null) {
viewModelScope.launch {
_loading.value = true
_error.value = null
service.getIPOs(status, type).fold(
onSuccess = { response ->
_ipos.value = response.ipos
_loading.value = false
},
onFailure = { exception ->
_error.value = exception.message
_loading.value = false
}
)
}
}
fun loadIPO(identifier: String) {
viewModelScope.launch {
_loading.value = true
_error.value = null
service.getIPO(identifier).fold(
onSuccess = { ipo ->
_ipos.value = listOf(ipo)
_loading.value = false
},
onFailure = { exception ->
_error.value = exception.message
_loading.value = false
}
)
}
}
}
// MainActivity.kt
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private val viewModel: IPOViewModel by viewModels()
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: IPOAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerView)
adapter = IPOAdapter()
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
observeViewModel()
viewModel.loadIPOs(status = "upcoming", type = "EQ")
}
private fun observeViewModel() {
lifecycleScope.launch {
viewModel.ipos.collect { ipos ->
adapter.submitList(ipos)
}
}
lifecycleScope.launch {
viewModel.loading.collect { loading ->
// Update loading state in UI
}
}
lifecycleScope.launch {
viewModel.error.collect { error ->
error?.let {
// Show error message
}
}
}
}
}