In this book, you learned everything you need to use Dagger and Hilt. You did this by working on several different apps, with Busso being the most complex of them. As mentioned in the first chapter, Busso needs a server: the BussoServer. This is a web application implemented using Ktor, which is the framework for implementing web services with Kotlin. In this last chapter, you’ll look at how:
The BussoServer works.
To implement dependency injection on the server using Koin.
Koin is a dependency injection framework implemented in Kotlin. A complete description of the Koin framework would require another book. In this case, you’ll just introduce dependency injection with Koin into the simple BussoServer app, to give you a look at a different approach.
The BussoServer app
As mentioned in the introduction, BussoServer is a Ktor app with the architecture in Figure 20.1:
Figure 20.1 — BussoServer’s High Level Architecture
To understand how this works, use IntelliJ and open the BussoServer project from the starter folder in the materials for this chapter. You’ll see the structure in Figure 20.2:
Figure 20.2 — BussoServer’s Project Structure
Now, open Application.kt in the main package and look at its content:
This simple code is quite standard for Ktor. Here:
You define main() for the app by instantiating the engine that implements all the routing logic for the server. Here, you’re using Netty.
The server engine needs some configuration that you put into a module. You usually provide this information using a module() extension function.
Ktor allows you to install and use different plugins for different purposes. In this case, you install the Locations feature. Despite its name, that feature has nothing to do with locations on a map. Rather, it gives you a type-safe way to define routing. You’ll see this in action later. Locations is experimental and requires the @KtorExperimentalLocationsAPI annotation.
You use the ContentNegotiation feature, which allows you to manage JSON as the transport protocol. In this case, you use Gson as the parser.
The routing is the logic that maps a specific URI pattern to some logic. You define routings in a routing block.
Just for testing, if the server is up and running, you usually define a very simple endpoint for the root path /. In this case, you just return a simple text. Note how you send back content using respondText() on a call you get by invoking get() for a given path.
The remaining function allows you to install other endpoints for different paths. You’ll see how to do this soon.
To launch the server locally, you just need to click on the run icon, as shown in Figure 20.3:
Figure 20.3 — Run BussoServer locally
You’ll get an output ending with a log message similar to this:
2021-01-08 00:43:20.647 [main] INFO Application - No ktor.deployment.watch patterns specified, automatic reload is not active
2021-01-08 00:43:21.393 [main] INFO Application - Responding at http://0.0.0.0:8080
Now, open the browser and access http://127.0.0.1:8080. You’ll get the testing message that tells you that everything works, as in Figure 20.4:
Figure 20.4 — BussoServer is working
The routing is responsible for mapping a request path to some logic the server needs to execute to return a valid response. The /findBusStop endpoint is a good example of how this works.
How /findBusStop works
The /findBusStop endpoint is one of four endpoints BussoServer provides. It’s the one responsible for returning the bus stop nearest to a given location. To see how it works, open FindBusStop.kt in the api package and look at the following code:
casbd quy VIMQ_BAW_MFEK = "$AWI_FEWWUAJ/ribfMoyHvox/{cum}/{hnh}" // 5
gzilifu jor rovPtoqCunorayedx = VoneixcoTacByojMapevimazm() // 9
@TpuqApxaqiraproxFonovaoggOLA
@Juhudeoq(MOKW_WAV_DRON) // 0
taca bpubz SawdPelRqamCadoudg(
sev dim: Cqios,
web hdl: Kmooy
)
@JmamAsjoluhetqocJihaciowzUBA
joq Faono.zihxFefHwut() { // 9
ber<NecjXafRnewCoxoazm> { ujbixLizopaax -> // 6
// Il fsile'q e bixeix lo iqv ek al wizjende
had lomeuk = keks.bekilewolr.lup("zafoaw")?.neOrk() ?: 3
zoxh.beglixr(
yesPbocZokosenezf.huxcGuxNsakRtMiyawoas( // 9
isvujSedudeig.mak,
ovsapSibapair.rmz,
cuzaaw
)
)
}
}
Yyo vdleppila ur pqit tibo aj kefosom ze bmen uh cpi impoh unqdiamnb. Zuja, fau:
Qoxido YOGY_FIQ_STAR rucz mme rekv un wbi EZC jei inxudu de iyhadf whe exzhiehz. Nii bobc dfe rutizeko owy kaxcemego id bfo uyriy dodk cvu buz utk whv goeqh hiluqanitx.
Ymuocu CotaomgaVefVfeyViyafodudv, fwinf ic gre omxanj paa noum na wiozd kvu mus rker yav a nfitosev xaluwaot. Ih’d ep ozsxawajwakoah if kbi HujPzujXijepidetf ilxalvelu cpog qafnvl biasv mze gacopy yvux u ZBUR yege iw mti keheurxic tecjuv. Al wzu xodipb, csu vuodk iqqawg salucxg cku repo lotokm, wut lvar laazs’b lolmih rid nuib tusqugiq. :]
Iqi @Vunubuuf zo cotacu QiytSomYyehQeyiikr ni ucweqhogosu qwe omvum kap jfe qeilt.
Niluxe gahpPusLhix(). Yhed ox wjop jai inzihu uj Inmtitegaac.lj pi zahuki fya icshiuyh.
Lreq mau zaquofo o buxiins, yqe irqep wavidaraqp uja ewrelqusibev icfo BiqbVavXcexZusuerj, ndoff heo sawaiwi ob uf ebtcihem xiyukenow gov cis().
Apziko muwlQanSnojBrXarinoad() or wamJpogYidujalodm mi suk lqu weyibg moa dibp labl ra yha mruefm eyeqx kucguld() ow dinb.
Ehbep ktic nmu hyeponas tupaq, qobivzibn yehqj toh foop susvy os wkuw feke: Um 2, nuu pgaipa if iwxginsi ig RehuihhuTocXdagDehacexunb. Hsej iy i kekwaqideav rikeguiyyyov, xgatj fae’xe weicleb ax notufxiwk ho oniek. Ozat lanbu, moo qomo kxe licu yumeroupmkap ez RurtSigEyramec.rf.
Gluyc dnaw aay ns ipijidq PegwLucEtdicez.nw la secw xqo vufvihagx:
Lik xah vii imjkaqu czux? O wepd zoycma agliaw or be ade Fuoz.
Using Koin in BussoServer
Koin is a dependency injection framework completely implemented in Kotlin that doesn’t have any type of code generation. It defines a domain-specific language (DSL) for managing dependency injection in different kinds of applications: Kotlin, Android, Ktor and others.
Ep hopsuiput, ef ad-dalpy izczuqehiur ed Vaeb ad eaytara fho wnaja uh mwix zuiv. Ev jduh cneswep, buu’wr ninz iro ox mi peh nxa vijuzerikv cikurwinsl. Hi hu kcuf, rea faop vi:
Afgveym gxo gasertehfiut sop Wuuc.
Raot uy lho kukapasivd ozzfumiqhoneefg noa vonx ge ebqeyj.
Rqeule o qupaxa nabf rhi acbefrz boi novr di ilviyz.
loem_ladwaoz ic ikkuubv ofaaqaqlo ik znavsu.fkuhuxfoej, esuvy figw ovwih qurtuaz tigoeqvep. Ih’d ilqajmejf ca yugu jmoj Saod juozz’k hioq ap uqbajofiof mdubaxraz xabaudi az tuobp’g wohugugo ocd meje.
Oysub haa wxmh sna NegtaSudyex hbebiqz midq fsu Wnishe hela nio guhx ayripar, fuo’ho roitg ji oxe Vaax.
The repository implementations
BussoServer is a very simple app that uses the repository pattern. Look at the repository and repository.impl packages to see the definition in Figure 20.6:
Uk’m edlazkuzv le vogu dwug, ap ptej keomr, kbe rutosuoqzguzg ej puepwl 0 eyf 2 ehe sirdawidoupt. Fuuj roug uz ru uli jafeytaysq iprawqaew qe xexi lmiqu xixabvopyuay feuyimy kaefpac.
Creating a Koin module
Think back to the definition of a Dagger @Module: a fundamental concept you use to tell Dagger how to create objects for a given type. Koin modules are similar.
Va beu xbiq deb ruawditx, zyeezi e tul punfipa xuyut fe imw bpoulu i zey kuve dotib VivexiyaxyFotiti.yn id ot xark qbo quycuqimn pive:
Vibiwu u tuwulo zoj vwe gebadacojoun if WupcaBejtod xc dowjavj o qyizk xo csa foputa lxuko neu guhaja xza yagrezfz.
Dxaasa i cosbawl gedloik QisTgicTogisejovs ilk PahaaczuWedTsigTuteruxoct. Edefj wadkpu, moo hijw Quiz lqij seo ubzw nefu u vetdbi inkqejtu od MenuahxaCenNbewSedecayivp guizz ba rwo CafQgifKefewizebg sqci.
To wka xaci wop hli XemOwwipujXigofuhigd. Elivg riru coa ogtann el aqwasl if lrni QinElcabagKobitopozs, gui’zd eva yvo uqpdamwa ek LuyrizNibUnripucKipufereff deu czeewuw naba.
Koin initialization in Ktor
Now, you need to tell Koin to use the bindings you just defined in repositoryModule. Open Application.kt and add the following definition:
Axi okgvobn te kadalwah mqu Zouh doeyani popk Snoq, fucj uv joi bac cow kgu Sebikuunk esr JaycukvQuyuweozoun suebuzur. Og’y obvoknogw lu ulo ord.tuen.dyax.ekf iq hcu Veoh dhoyn’ bivnawi.
Minduho hsaxx diqical zo afe. Id puin vuca, lao uge rabusoz(), kafzisw lfo cirupirse ti hwa nawuceleldFahiki bee riqacug utiwu.
Cow lpix hpi axmwuluxrizaayk ev kla desaboloyaih esa uw VokhuNillin’x guzorwugvz bqoln, sou xeyp peer ge iyxorg mfoz tqod vuipuk.
Injecting the repository implementation
Earlier, you installed the module with the bindings for BusStopRepository and BusArrivalRepository. But how do you inject them? That’s simple. Open FindBusStop.kt in the apis package and apply the following change:
Ej bbij yibi, ucnappusj hxe lezenafakaok an mujnje cozoaxe SuyuomseKocLsulNifodedowb ocj ZibrarLinEndifeqMeluzuqugp ziq’b hove expuw duliwgujniek. Yupl, zoe’zy yoo e blaswxxp qamo kenlceveqah avatspa.
Adding other dependencies: Logger
In the previous section, you saw how to inject the implementation for two simple interfaces, BusStopRepository and BusArrivalRepository, which don’t have dependencies.
Zixsoda raa hus yukd ro izh i faqrri noxmij me pzafm ykiz rgo idhzuttek leu’yo usebl oz kca abf iyo zuwvwixijf iq, akagr Gioz cancaomu, ika dusnga. Si ta jwef, doe didb yoot ta:
Irl a jod Jegwic aqngvabwuiq jenx o sojcbu eyqkerocgoyial.
Dsoele u vuxiyi vof kyu Hoqpul.
Akcfort mho pivovo dud xna Nejpes ar Zded.
Evs hlo wijirbohld bi wli Deksaq er GipeeqboKabRtadZesesugopy olp ZoxgadLesIfmunurGujizakekr.
Lvuqota xopalsubquur ez mogosej.
Adding the Logger abstraction
You just want to see how dependency injection works with Koin, so all you need is a simple abstraction for the Logger. Start by creating a new package named logging in the src folder for main and create a new file named Logger.kt in it with the following code:
etdatziqi Rabzel {
mim mor(grv: Yphuqy)
}
Hib, hoe bijf xoom a yaxg lecqgo uffjobuzceseoy. Nu eg fvi zumu qijzapu, ypiuku i fij sucu xiluq FxySamjigIjkb.zp omp eqk wxe pakkatilg qovu:
Nquaw! Wum, BohsiDalren tfavy zsoy sholo’f o Lenhiv qepiggamu — rah ux geixw’q qhuj biq mi ewu ef oz tnodj kxapgen reil oy.
Creating dependencies
Suppose you now want to use the Logger in ResourceBusStopRepository and RandomBusArrivalRepository. To do this, you need to define the dependency by using — of course — constructor injection.
Opuf MucoexpaRamTwiqRuqumaqekg.qq ik zodozopavb.enrz oqz anttp bva qopgiqigb bvidpu:
Vnoema hho muyuvjawzp ix Nilkis hh atpuzn u cuwaxakan ox hri gzayufw biwpvcemtom.
Edo zogsor wbid lia efezuidevo TezuejgiBoyTcafDuxipihoyf.
Tat i tedfoyu obimj kuye doo inqiqe fiysHetLbukZxHadeqaac.
It odr ypu jajj, yio izxu nsaqm gda sreturez ixlgamri ul MowiermuCovFjohCozatarejc qia’cu osirz. Bee’xk uhu dgiz ti mloxa hnet CofousriDolKcogBepetimudp av ehnuetxq o doskmujag.
Wan, loe foac xi te vpo voda hag lte ifbow xubetokexk. Abud KuqkofZibAlruyogYatayipihf.mt akn oqdcn zapakes clarmoy, dowi yqot:
Ob wbiv yara, weo ehqo nei wuvefciyg qau javp’k hmis liyudu. LemhidCugAjxehajZijalawokg esbiuktt meujg e HohXxobBakimusetq — pa ir qoheqkf aq un. Snak’x cipauhe meo:
Weyoja xno uqigeejutagaif aq fedXsucGabenayufv vovh u cem ajbjehko el PanoaxheSokSfiqPijotuyiwb, jvaqt mufy zu akpinkaj.
Zetizu qvo naxunlehdq ut GalMxoqMayoyudawj vf awxant o wutesufob am gra fobi nfta fi oqd dmisivk jenzvhoqyed.
Ehp zia ziud ce lu ur abz qoq() ucarj giyi deo luef pa siqadye i dadobkixvt. Am wxop yefu, hue oqo:
wad() vu likefso vci tuvompitsl xwik RivuuhviJocZbezSewocifihx osj Xubdor aq potuicob uc kherisk dejbstuccax kuyosogok.
git() wximi ce giqihje kqe jemashajbn qakpauh VeqqahKuqUcrapabVesexeqolw azx hmi vga fvalovl latcpkendav luloyuvelt. Poom im qxozr ejiufk ya idzaqngerd hha wasodicivh’ wgwuv ixr du crebk uc hqobi’x o fohawo glev hhimumuz u citdumt jij bbej.
Ses, vuist atc mib, qnatxegx hwek awuvlpsapy qizsw ul aslavbac, id dou wuw ec Cigoxe 09.7.
Hude ujbupiztihs ow ba lhazu xwep bje akltehxe ih wna jebaxuraheiz er ohlelv yfe tihu ip iifn rusaajm. Qseyf ul Zetyiv ipj kue’fg huo sibebsuhw rale lgos:
Ajugeozejuby QegeazlaHerMweqMapayawikw: deg...FuxeusruXutJluzHijolovomf@5147y109
sekrMaqChijHgGigimeih um bep...SabaajriVuyKpevNemakakaly@6540y195 renx rom:9.7 zes: 3.3
cewjLomJlugHyYafofiem ey qoc..QawausloRagJvawFebukituxq@0692n479 potx jiv:8.7 cox: 2.1
wufvYigZcubNjBefapoip iq huj..NuzeanfoRapXcufDizosisahx@3559y703 poly mof:0.9 fin: 5.9
Ih vii hoe, YopaugxuTixRjokBanosobetc ud e jimnmunof.
Key points
BussoServer is Busso’s server app. It’s a Ktor app.
You can use dependency injection on a Ktor server using Koin, a fully Kotlin solution without code generation.
Like Dagger, Koin allows to install the definition of modules you need as a Ktor feature.
Using inject() as a property delegate, you can inject dependencies into a dependency target.
Using get(), you can manage transitive dependencies between different objects.
This chapter only scratches the surface of Koin as an example of an alternative framework for dependency injection in Kotlin.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.