Hello, :wave::skin-tone-4: I was wondering if thi...
# koin
h
Hello, 👋🏽 I was wondering if this would still be a good manner to inject dependencies using Koin in Top level function. https://stackoverflow.com/a/50840374 Does anyone have a better approach for it?
t
I don't think so. Eventually you should create a single instance within your Koin graph instead of using top level functions which require dependencies.
h
What do you mean is: Wrap up this "top level function" in a class and probably inherit from KoinComponent to allow the injection of the class I want?
a
You can use directly the global context:
GlobalContext.get().get()
in next Koin version, it will be more
defaultContext().get()
t
@Helio I acutally meant to use a class with dependencies.
KoinComponent
should not be necessary then.
a
yep 👍
h
Hello again, First of all, I would like to thank you both for your quick response. 🙂 • We are currently using Koin 2.2.2 for Ktor. I ended up going with the GlobalContext as suggested by Arnaud, I will try to explain why, even though it might sound confusing (I know how these things are.. haha). Also, it worth saying that we will keep watching for updates. to get rid of the second
get()
. @tynn, in our scenario, we have a Ktor Controller (which is used to declare our apis) and for this specific case we have this “Helper” class, which handle some Generic Top Level functions for us. For example, in our Controller, we have the following
snippet
. There you can see that we are injecting a UseCase class.
Copy code
fun Route.tokenApi() {
    val createAccessTokenUseCase: CreateAccessTokenUseCase by inject()

    route("/token") {
        post("/build") {
            val buildInfo = call.principal<Principal>().getBuildInfo()
            createAccessTokenUseCase.createBuildToken(buildInfo,
                    TokenatorPermissionGroupProvider.getGroupsFor(call.request.local.uri)).let { call.respond(HttpStatusCode.Created, it) }
        }
}
This line
val buildInfo = call.principal<Principal>().getBuildInfo()
reference our Top level function
getBuildInfo()
. This function will use different classes depending on the
Principal
. The way I was doing before, I was injecting the class I wanted in the Controller context and passing it to my function like this
getBuildInfo(injectedClassForPrincipal1)
. Complete example:
Copy code
fun Route.tokenApi() {
    val createAccessTokenUseCase: CreateAccessTokenUseCase by inject()
    val myInjectedClassForPrincipalOne: MyInjectedClassForPrincipalOne by inject()
    route("/token") {
        post("/build") {
            val buildInfo = call.principal<Principal>().getBuildInfo(myInjectedClassForPrincipalOne)
            createAccessTokenUseCase.createBuildToken(buildInfo,
                    TokenatorPermissionGroupProvider.getGroupsFor(call.request.local.uri)).let { call.respond(HttpStatusCode.Created, it) }
        }
}
Soon, we will need to make
getBuildInfo()
able to handle a request for a different principal… Which we would need to add another parameter to
getBuildInfo(injectedClassForPrincipal1, injectedClassForPrincipal2)
. Complete example:
Copy code
fun Route.tokenApi() {
    val createAccessTokenUseCase: CreateAccessTokenUseCase by inject()
    val myInjectedClassForPrincipalOne: MyInjectedClassForPrincipalOne by inject()
    val myInjectedClassForPrincipalTwo: MyInjectedClassForPrincipalTwo by inject()
    route("/token") {
        post("/build") {
            val buildInfo = call.principal<Principal>().getBuildInfo(myInjectedClassForPrincipalOne, myInjectedClassForPrincipalTwo)
            createAccessTokenUseCase.createBuildToken(buildInfo,
                    TokenatorPermissionGroupProvider.getGroupsFor(call.request.local.uri)).let { call.respond(HttpStatusCode.Created, it) }
        }
}
Using the GlobalContext.get().get(), doesn’t make necessary for me to be injecting class by class. I can just reference them in the Top level functions it should be used. Also, IMHO, I don’t think for this scenario it makes sense to let my TokenController knows about (myInjectedClassForPrincipalOne, myInjectedClassForPrincipalTwo). Please, let me know if you think it makes sense or if it doesn’t make sense at all (I’m relative new to Kotlin). Also, I’m always keen to hear different point of views.
a
yes a bit like compose, it can be a scenario to just inject somewhere at top level a needed instance. Seems ok then 👍
h
Awesome! Thanks for confirming. :)