Hi folks. I am new to KMM and trying to create a g...
# ktor
m
Hi folks. I am new to KMM and trying to create a generic function for api calling using ktor with 
reified
  and it seems to work fine with 
android
 but throws an error in 
iOS
This is my common api call return in Shared file.
Copy code
@Throws(Exception::class)
suspend inline fun<reified T> post(url: String, requestBody: HashMap<String, Any>?) : Either<CustomException, T> {
    try {
        val response = <http://httpClient.post|httpClient.post><T> {
            url(BASE_URL.plus(url))
            contentType(ContentType.Any)
            if (requestBody != null) {
                body = requestBody
            }
            headers.remove("Content-Type")
            headers {
                append("Content-Type", "application/json")
                append("Accept", "application/json")
                append("Time-Zone", "+05:30")
                append("App-Version", "1.0.0(0)")
                append("Device-Type", "0")
            }
        }
        return Success(response)
    }  catch(e: Exception) {
        return Failure(e as CustomException)
    }
}
It works good in android if I call it like this :-
Copy code
<http://api.post|api.post><MyDataClassHere>(url = "url", getBody()).fold(
    {
        handleError(it)
    },
    {
        Log.d("Success", it.toString())
    }
)
But I am not able to get it run on iOS devices it shows me error like this :- `some : Error Domain=KotlinException Code=0 "unsupported call of reified inlined function `com.example.myapplication.shared.apicalls.SpaceXApi.post`" UserInfo={NSLocalizedDescription=unsupported call of reified inlined function
<http://com.example.myapplication.shared.apicalls.SpaceXApi.post|com.example.myapplication.shared.apicalls.SpaceXApi.post>
, KotlinException=kotlin.IllegalStateException: unsupported call of reified inlined function
<http://com.example.myapplication.shared.apicalls.SpaceXApi.post|com.example.myapplication.shared.apicalls.SpaceXApi.post>
, KotlinExceptionOrigin=}` Any help in this is  appreciated. Thanks
m
m
Nope this won't. I need use ktor common api call for both android and iOS. This doesn't make any sense for using KMM.
m
Do you call
suspend inline fun<reified T> post()
directly from Swift?
m
yes
m
Ah okay. You cannot use
reified
functions from Swift afaik. You’ll have to provide a Swift-specific function in Kotlin for iOS only that works without
reified
and calls
post()
internally. How do you call it?
m
exactly so do i need to create every time a new function if I need to do some api call to specify it's return type ?
m
I think so. Kotlin cannot work directly with Swift types, at least for now.
Kotlin doesn’t even interop fully with Swift, only with ObjC. It just works “well enough” with Swift.
m
This is how I call it in swift :-
<http://api.post|api.post>(url: "api/login", requestBody: map) { Result,arg *in*
*if* (arg == *nil*) {
        Result?.fold(failed: { (error)
in
        
}, succeeded: { (response) *in*
        
})
      
} *else* { }
    } I always knew am doing something wrong as I am not specifying what kind of response do I need in return but I didn't how to do that
If we need to create different functions everytime we need to call a new api that would increase a lot of lines and has no use as we are doing the same thing everywhere.
m
What I would do is to create an
ApiClient
in Kotlin like that:
Copy code
interface ApiClient {
   suspend fun logIn(…): …
   suspend fun createBlogPost(…): …
   // etc
}
And then use that one from Android and iOS. The platforms don’t need to know about
api/login
endpoints etc. That can be hidden behind a multiplatform interface.
I’d say it simplifies code. Otherwise you’re replicating logic on both platforms - e.g. what endpoint has what path.
It also makes the shared code much easier to use. Platform code doesn’t need to know about API endpoints. They can simply use autocompletion of the
ApiClient
functions.
m
Yes Gotcha that ain't what I expected but it looks like the only solution for now.
j
Its not bad in general to abstract layers with interfaces, gives you the freedom to change things with minimal impact and improves testability
m
Agreed but won't it be good if we have a single function for all get and post api calling instead of different having a different function for all different api's ?
m
Behind the interface it's still the two functions. For the API-consuming clients an interface is much better to use than raw get/post requests where they need to know more implementation and you have to duplicate logic across platforms.
m
Okay sounds good do you have any sample project or a blog post which might explain best practices for the same ?
j
You can try looking up clean coding or read up on the s.o.l.i.d. principles. Best practices in general is an opinionated topic, but id say every class/function needs a single purpose. If you have a class that collects information, fires backend requests and then stores it into some other place is already too much (even if all these topics are related) splitting up into different single purpose layers using lots of abstractions is the way to go. For example: repository should not know about db implementation or network implementation, it should just connect the dots there. So making direct api calls from repository should not be done, api calls should be abstracted behind some api interface, which can do anything it wants as long as it returns the expected object. Same way that a repository should not run db queries, it should ask the local storage persistence class to fetch some data. The implementation of that could then be anything you want (db, files)
🙌 3
m
Great Thanks for the explanantion.
207 Views