TW Controllers
Tegral Web Controllers provides classes and various utilities for building Ktor applications within Tegral.
Features include:
- Letting Tegral manage your application settings and application lifecycle management
- Defining your own Ktor modules and controllers as Tegral DI components, and automatically installing them to their appropriate applications.
- Multiple Ktor applications support within the same DI environment
- Easy Ktor testing within the DI environment with controllers and modules
Package name | Catalog dependency | Full Gradle name |
---|---|---|
tegral-web-controllers | tegralLibs.web.controllers | guru.zoroark.tegral:tegral-web-controllers:VERSION |
tegral-web-controllers-test | tegralLibs.web.controllers.test | guru.zoroark.tegral:tegral-web-controllers-test:VERSION |
Installation
Install the Controllers feature within your application (you do not need to do this if using AppDefaults/AppDSL).
install(WebControllersFeature)
Getting Started
The Controllers extension uses three types of components to do its job.
Note that you will still need to register your components using the usual put()
functions.
KtorApplication
The primary class that will host the actual Ktor application needs to inherit from KtorApplication
.
This class is responsible for providing the core configuration of the application. This is done by overriding the settings
property.
Behind the scenes, this is the class that "holds" the Ktor application instance and is responsible for startup and stopping. All of this is done in KtorApplication
.
You do not need to add this class yourself when using AppDSL/AppDefaults. A default application class is created for you with sane defaults and uses the web configuration to configure the port and host.
Here is an example:
class MyApplication(scope: InjectionScope) : KtorApplication(scope) {
override val settings get() = KtorApplicationSettings(Netty, port = 8080)
}
Do not forget the get()
after val settings
, otherwise you will be performing an unsafe injection if you use DI components when building your settings object.
KtorModule
A Ktor module (not to be confused with a Tegral DI module) is a class that inherits from KtorModule
. This is a module in the Ktor sense: an extension function on top of Application
that adds features, routes, etc.
// As with any regular Tegral DI component, the 'scope: InjectionScope' parameter
// is optional if you do not need it.
class MyModule(scope: InjectionScope) : KtorModule() {
override fun Application.install() {
install(...) {
...
}
routing {
...
}
}
}
KtorController
Ktor controllers are identical to Ktor modules but are more convenient for adding routes and eliminate the need to explicitly call routing { }
in the module.
// As with any regular Tegral DI component, the 'scope: InjectionScope' parameter
// is optional if you do not need it.
class MyController(scope: InjectionScope) : KtorController() {
override fun Routing.install() {
get("/hello") {
call.respondText("Hello World!")
}
}
}
Fundefs
Fundefs and fundefs support in Tegral Web are both experimental and subject to change.
Fundef support must be enabled in Tegral Web using the following in your tegral
block:
tegral {
install(WebControllersFeature) {
enableFundefs = true
}
}
Ktor modules and controllers can also be defined using fundefs. This is a shorter syntax that is more convenient for controllers and modules that do not require complex logic.
Fundefs that have Ktor's Application
or Routing
class as a receiver are installed as Ktor modules and Ktor controllers respectively. For example, this:
class GreetingController(scope: InjectionScope) : KtorController() {
private val greetingService: GreetingService by scope()
override fun Routing.install() {
get {
call.respondText(greetingService.generateGreeting())
}
}
}
tegral {
put(::GreetingController)
}
Can be written as:
@Fundef
fun Routing.greetingController(greetingService: GreetingService) {
get {
call.respondText(greetingService.generateGreeting())
}
}
tegral {
install(WebControllersFeature) {
enableFundefs = true
}
put(Routing::greetingController)
}
It is not currently possible to change the application name or priority order for controllers or modules defined this way.
Installation order
In case you need to control the order in which your components are installed, you can pass a priority integer to KtorController
and KtorModule
constructors.
class MyController(scope: InjectionScope) : KtorController(10) {
...
}
class MyModule(scope: InjectionScope) : KtorModule(200) {
...
}
By default:
- Applications'
setup()
have a priority ofInt.MAX_VALUE
and are always installed first. - Modules have a priority of 500.
- Controllers have a priority of 300.
Modules and controllers are installed in the decreasing order of their priority, from largest to smallest.
Controllers and modules that have the same priority are installed in an arbitrary order. Make sure you use priorities if you need a specific order, even if the default order happens to just work for you.
Multiple Ktor apps
Tegral Web Controller supports hosting multiple independent Ktor applications under the same environment.
In order to differentiate between applications (e.g. which controllers are installed where), you can give your applications a name and tell your controllers and modules to install themselves only onto applications of a specific name:
const val AppOneName = "app-one"
const val AppTwoName = "app-two"
class AppOne(scope: InjectionScope) : KtorApplication(scope, AppOneName) {
...
}
class AppTwo(scope: InjectionScope) : KtorApplication(scope, AppTwoName) {
...
}
class ModuleA : KtorModule(restrictToAppName = AppOneName) {
// This module is only installed on AppOne
...
}
class ModuleB : KtorModule(restrictToAppName = AppTwoName) {
// This module is only installed on AppOne
...
}
If you do not specify a name for your application, it gets the name null
by default. null
is a valid name and has no special meaning (other than that it is the name used by default).