Skip to main content

Network Module

Data layer module providing Ktor-based HTTP client with automatic error mapping, token management, and type-safe API definitions.

implementation("com.github.wahidabd.miru-sdk:network:<version>")

ApiService

Base class for all remote data sources. Provides HTTP methods that automatically map responses to Resource<T>:

class ProductApi(httpClient: HttpClient) : ApiService(httpClient) {

suspend fun getProducts(): Resource<ApiResponse<List<ProductDto>>> =
get("products")

suspend fun getProduct(id: Int): Resource<ApiResponse<ProductDto>> =
get("products/$id")

suspend fun createProduct(body: CreateProductRequest): Resource<ApiResponse<ProductDto>> =
post("products", body = body)

suspend fun updateProduct(id: Int, body: UpdateProductRequest): Resource<ApiResponse<ProductDto>> =
put("products/$id", body = body)

suspend fun deleteProduct(id: Int): Resource<ApiResponse<Unit>> =
delete("products/$id")
}

Available HTTP Methods

MethodFunctionParameters
GETget(path, params?)Query parameters
POSTpost(path, body?, params?)Request body + query params
PUTput(path, body?, params?)Request body + query params
PATCHpatch(path, body?, params?)Request body + query params
DELETEdelete(path, params?)Query parameters

Query Parameters

suspend fun searchProducts(query: String, page: Int): Resource<ApiResponse<List<ProductDto>>> =
get("products/search", params = mapOf("q" to query, "page" to page.toString()))

SafeApiCall

Internally, all API calls are wrapped in safeApiCall which catches exceptions and maps them to AppException:

HTTP StatusException
401AppException.UnauthorizedException
403AppException.ForbiddenException
404AppException.NotFoundException
5xxAppException.ServerException(code)
TimeoutAppException.TimeoutException
No connectionAppException.NetworkException
OtherAppException.UnknownException

Token Management

TokenProvider

Implement the TokenProvider interface to handle auth tokens:

class MyTokenProvider : TokenProvider {
override suspend fun getAccessToken(): String? =
prefs.getString("access_token")

override suspend fun getRefreshToken(): String? =
prefs.getString("refresh_token")

override suspend fun saveTokens(accessToken: String, refreshToken: String) {
prefs.putString("access_token", accessToken)
prefs.putString("refresh_token", refreshToken)
}

override suspend fun clearTokens() {
prefs.remove("access_token")
prefs.remove("refresh_token")
}

override suspend fun isLoggedIn(): Boolean =
getAccessToken() != null
}

TokenEventBus

Observe auth state changes globally:

TokenEventBus.events.collect { event ->
when (event) {
TokenEvent.ForceLogout -> navigateToLogin()
TokenEvent.TokenExpired -> refreshToken()
TokenEvent.TokenRefreshed -> retryRequest()
}
}

NetworkConfig

Configure the HTTP client at initialization:

NetworkConfig(
baseUrl = "https://api.yourapp.com/v1/",
enableLogging = BuildConfig.DEBUG,
connectTimeoutMs = 30_000L,
requestTimeoutMs = 30_000L,
)

ApiResponse

Standard wrapper for API responses:

@Serializable
data class ApiResponse<T>(
val data: T? = null,
val message: String? = null,
val status: Boolean = true
)