iT邦幫忙

2021 iThome 鐵人賽

DAY 3
0
Modern Web

基於 Kotlin Ktor 建構支援模組化開發的 Web 框架系列 第 3

[Day 3] 以 Ktor Module 實作模組化開發

Ktor Module

Ktor Module 可以用來組織程式碼,本身僅是一個 Application 類別的 extension function,讓 server 啟動時執行而已。Ktor 並沒有規定 Module 內部應該如何實作,也沒有限制 Module 的顆粒度要多大,官方文件只提到 module 可以是某些 plugin 及 routes 的集合。例如我可以實作一個 Shutdown module,其 extension function 的內部實作是安裝 Ktor ShutdownUrl plugin,藉此增加1個 GET route,讓外界呼叫此 GET API 後能停止 server。

Multi-Project with Ktor Module

實作上,我把每個子專案當作是一個 Ktor module,而且都依賴於 infrastrcture module。infrastrcture module 負責安裝 Ktor Plugin,提供底層的函式庫及功能。我建立了2個子專案 ops 及 club,透過設定 ktor.application.modules 屬性值,Ktor 會在啟動時依序執行這3個 module 的 extension fuction。設定時要注意 infra module 必須要放在第一個位置。

application {
    modules = [
        fanpoll.infra.ApplicationKt.main,
        fanpoll.ops.OpsProjectKt.opsMain,
        fanpoll.club.ClubProjectKt.clubMain
    ]
}

其中 infra module 的 extension function 內部實作是負責初始化 Ktor plugin 及 ProjectManager

fun Application.main() {
    install(LoggingFeature)
    install(DatabaseFeature)
    install(RedisFeature)
    install(Authentication)
    // ...以下省略
    koin {
        modules(
            module(createdAtStart = true) {
                single { ProjectManager(get()) }
            }
        )
    }
    // ...以下省略
}

club module 的 extension function 內部實作是負責初始化 club 專案。第一步是先透過 Koin DI 取得 ProjectManager 物件,然後載入 club 專案設定檔,最後再建立 club Project 物件並註冊至 ProjectManager

每個子專案可各自定義以下項目,infra module 再根據 project 物件執行相對應的功能

  • 使用者類型及其角色
  • 驗證 API 請求的方式
  • 訊息通知類型
  • OpenAPI 文件
fun Application.clubMain() {
    val projectManager = get<ProjectManager>()
    val projectConfig = ProjectManager.loadConfig<ClubConfig>(ClubConst.projectId)
    projectManager.register(
        Project(
            ClubConst.projectId,
            projectConfig.auth.principalSourceAuthConfigs,
            ClubUserType.values().map { it.value },
            ClubOpenApi.Instance,
            ClubNotification.AllTypes
        )
    )
    // ...以下省略
}

class Project(
    override val id: String,
    val principalSourceAuthConfigs: List<PrincipalSourceAuthConfig>,
    val userTypes: List<UserType>,
    val projectOpenApi: ProjectOpenApi,
    val notificationTypes: List<NotificationType>? = null
) : IdentifiableObject<String>()

今天從程式開發層面說明如何使用 Ktor Module 進行模組化開發,明天將會從建置部署層面切入,說明如何使用 Gradle Multi-Project Builds 建置專案、還有使用 Gradle Shadow Plugin 及 Docker Compose 打包部署。


上一篇
[Day 2] 從單體式遷移至微服務架構,支援模組化開發的 Web 框架可以解決什麼問題?
下一篇
[Day 4] 使用 Gradle Multi-Project Builds X Shadow Plugin X Docker Compose 建置、打包、部署
系列文
基於 Kotlin Ktor 建構支援模組化開發的 Web 框架30

尚未有邦友留言

立即登入留言