6 Create minimal Server-API for client tests - basics

This commit is contained in:
Hartmut Bauer committed 2026-02-10 00:25:53 +01:00
1 parent 5ce25ff422
commit b8f924b578
17 files changed
+107 -37

No files matched your search

+2 -2
View File
@@ -1,3 +1,3 @@
#auto generated #auto generated
#Sun Feb 08 23:42:46 CET 2026 #Mon Feb 09 23:38:51 CET 2026
build.number=224 build.number=226
@@ -23,7 +23,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.keinekekse.app.books.generated.resources.Res import net.keinekekse.app.books.generated.resources.Res
import net.keinekekse.app.books.generated.resources.compose_multiplatform import net.keinekekse.app.books.generated.resources.compose_multiplatform
import net.keinekekse.app.books.ui.theme.AppTheme
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.koin.compose.koinInject import org.koin.compose.koinInject
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
@@ -33,13 +32,13 @@ private val logger = KotlinLogging.logger {}
@Composable @Composable
@Preview @Preview
fun App() { fun App() {
/*MaterialTheme*/ MaterialTheme {
/* /*
eigenes Theme -> https://material-foundation.github.io/material-theme-builder/ eigenes Theme -> https://material-foundation.github.io/material-theme-builder/
den Download in den source code übernehmen (in Theme.kt sind Anpassungen nötig) den Download in den source code übernehmen (in Theme.kt sind Anpassungen nötig)
per default hat die generierte Klasse den Namen AppTheme. per default hat die generierte Klasse den Namen AppTheme.
*/ // AppTheme {
AppTheme { */
val test = koinInject<TestAuth>() val test = koinInject<TestAuth>()
var showContent by remember { mutableStateOf(false) } var showContent by remember { mutableStateOf(false) }
Column( Column(
@@ -81,8 +80,12 @@ class TestAuth(val httpClient: HttpClient) {
private val srv = "https://kas.keinekekse.net/" private val srv = "https://kas.keinekekse.net/"
suspend fun request(url: String) { suspend fun request(url: String) {
logger.debug { "connecting" } logger.debug { "connecting" }
val response = httpClient.get(srv + url) // val response = httpClient.get(srv + "testdb/books")
// val books: List<Book> = response.body()
val response = httpClient.get(srv + url + "testdb/books")
val body = response.bodyAsText() val body = response.bodyAsText()
logger.debug { "call to $url" } logger.debug { "call to $url" }
logger.debug { response.status } logger.debug { response.status }
logger.debug { body } logger.debug { body }
@@ -4,13 +4,13 @@ import net.keinekekse.version.Version
object VERSION: Version { object VERSION: Version {
override val version = "1.0.0" override val version = "1.0.0"
override val fullVersion = "1.0.0+build.224" override val fullVersion = "1.0.0+build.226"
override val major = 1 override val major = 1
override val minor = 0 override val minor = 0
override val patch = 0 override val patch = 0
override val preRelease = "" override val preRelease = ""
override val buildMetadata = "build.224" override val buildMetadata = "build.226"
override val buildDate = "2026-02-08T22:42:46.561391Z" override val buildDate = "2026-02-09T22:38:51.084372Z"
override val displayName = "Books App" override val displayName = "Books App"
override val copyright = "Copyright (c) 2026 Hartmut Bauer" override val copyright = "Copyright (c) 2026 Hartmut Bauer"
override val name = "books" override val name = "books"
+2 -2
View File
@@ -1,3 +1,3 @@
#auto generated #auto generated
#Sun Feb 08 23:42:57 CET 2026 #Tue Feb 10 00:04:01 CET 2026
build.number=43 build.number=50
@@ -3,10 +3,7 @@ package net.keinekekse.app
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
import io.ktor.server.application.* import io.ktor.server.application.*
import net.keinekekse.app.server.VERSION import net.keinekekse.app.server.VERSION
import net.keinekekse.app.server.config.configureDatabase import net.keinekekse.app.server.config.*
import net.keinekekse.app.server.config.configureKoin
import net.keinekekse.app.server.config.configureRouting
import net.keinekekse.app.server.config.configureSecurity
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
@@ -22,13 +19,22 @@ fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
//} //}
fun Application.module() { fun Application.module() {
logger.info { "\n**\n** Starting ${VERSION.displayName} - ${VERSION.description} ${VERSION.fullVersion}\n**" } logger.info {
"""
**
** Starting ${VERSION.displayName} - ${VERSION.description} ${VERSION.fullVersion}
**
""".trimIndent()
}
configureSerialization()
configureKoin() configureKoin()
configureSecurity() configureSecurity()
configureRouting()
configureDatabase() configureDatabase()
configureRouting()
/* // DB-Test /* // DB-Test
transaction { transaction {
@@ -3,14 +3,14 @@ package net.keinekekse.app.server
import net.keinekekse.version.Version import net.keinekekse.version.Version
object VERSION: Version { object VERSION: Version {
override val version = "0.1.0-beta.1+build.43" override val version = "0.1.0-beta.1+build.50"
override val fullVersion = "0.1.0-beta.1+build.43" override val fullVersion = "0.1.0-beta.1+build.50"
override val major = 0 override val major = 0
override val minor = 1 override val minor = 1
override val patch = 0 override val patch = 0
override val preRelease = "beta.1" override val preRelease = "beta.1"
override val buildMetadata = "build.43" override val buildMetadata = "build.50"
override val buildDate = "2026-02-08T22:42:57.727025Z" override val buildDate = "2026-02-09T23:04:01.715682Z"
override val displayName = "kAS" override val displayName = "kAS"
override val copyright = "Copyright (c) 2026 Hartmut Bauer" override val copyright = "Copyright (c) 2026 Hartmut Bauer"
override val name = "server" override val name = "server"
@@ -2,12 +2,12 @@ package net.keinekekse.app.server.config
import io.ktor.server.application.* import io.ktor.server.application.*
import net.keinekekse.app.server.di.KoinApp import net.keinekekse.app.server.di.KoinApp
import org.koin.dsl.koinConfiguration import org.koin.ktor.plugin.Koin
import org.koin.logger.slf4jLogger import org.koin.logger.slf4jLogger
import org.koin.plugin.module.dsl.withConfiguration import org.koin.plugin.module.dsl.withConfiguration
fun Application.configureKoin() { fun Application.configureKoin() {
koinConfiguration { install(Koin) {
slf4jLogger() slf4jLogger()
withConfiguration<KoinApp>() withConfiguration<KoinApp>()
} }
@@ -6,6 +6,7 @@ import io.ktor.server.auth.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import net.keinekekse.app.server.VERSION import net.keinekekse.app.server.VERSION
import net.keinekekse.app.server.testdb.testDbRoute
private val logger = KotlinLogging.logger {} private val logger = KotlinLogging.logger {}
@@ -22,5 +23,7 @@ fun Application.configureRouting() {
call.respondText("Ktor ${VERSION.displayName} ${VERSION.fullVersion} - principal=${principal?.name}") call.respondText("Ktor ${VERSION.displayName} ${VERSION.fullVersion} - principal=${principal?.name}")
} }
} }
testDbRoute()
} }
} }
@@ -0,0 +1,17 @@
package net.keinekekse.app.server.config
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
fun Application.configureSerialization() {
install(ContentNegotiation) {
json(
json = kotlinx.serialization.json.Json {
prettyPrint = true
// isLenient = true
ignoreUnknownKeys = true
}
)
}
}
@@ -1,6 +1,6 @@
package net.keinekekse.app.server.testdb.db package net.keinekekse.app.server.testdb.db
import net.keinekekse.app.server.testdb.model.* import net.keinekekse.app.book.model.*
import org.jetbrains.exposed.v1.core.dao.id.EntityID import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.dao.IntEntity import org.jetbrains.exposed.v1.dao.IntEntity
@@ -1,5 +1,9 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.server.testdb.model
import net.keinekekse.app.book.model.Artist
import net.keinekekse.app.book.model.Book
import net.keinekekse.app.book.model.Series
interface BookRepository { interface BookRepository {
suspend fun allBooks(): List<Book> suspend fun allBooks(): List<Book>
suspend fun bookById(id: Int): Book? suspend fun bookById(id: Int): Book?
@@ -1,12 +1,21 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.server.testdb.model
import net.keinekekse.app.book.model.Artist
import net.keinekekse.app.book.model.Book
import net.keinekekse.app.book.model.Series
import net.keinekekse.app.server.testdb.db.BookDAO
import net.keinekekse.app.server.testdb.db.daoToModel
import org.jetbrains.exposed.v1.jdbc.transactions.suspendTransaction
import org.koin.core.annotation.Single
@Single
class BookRepositoryImpl : BookRepository { class BookRepositoryImpl : BookRepository {
override suspend fun allBooks(): List<Book> { override suspend fun allBooks(): List<Book> = suspendTransaction {
TODO("Not yet implemented") BookDAO.all().map(::daoToModel)
} }
override suspend fun bookById(id: Int): Book? { override suspend fun bookById(id: Int): Book? = suspendTransaction {
TODO("Not yet implemented") BookDAO.findById(id)?.let { daoToModel(it) }
} }
override suspend fun booksBySeries(series: Series): List<Book> { override suspend fun booksBySeries(series: Series): List<Book> {
@@ -0,0 +1,28 @@
package net.keinekekse.app.server.testdb
import io.ktor.http.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import net.keinekekse.app.server.testdb.model.BookRepository
import org.koin.ktor.ext.inject
fun Route.testDbRoute() {
val repository: BookRepository by inject<BookRepository>()
// authenticate("auth-KC") {
route("/testdb") {
get("/books") {
// call.respondText("Test DB route")
val books = repository.allBooks()
call.respond(books)
}
get("/book/{id}") {
// TODO safe toInt conv
val id = call.parameters["id"]!!.toInt()
repository.bookById(id)?.let { call.respond(it) }
?: call.respondText("Book with id $id not found", status = HttpStatusCode.NotFound)
}
}
// }
}
@@ -1,4 +1,4 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.book.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -1,4 +1,4 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.book.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -1,4 +1,4 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.book.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -1,4 +1,4 @@
package net.keinekekse.app.server.testdb.model package net.keinekekse.app.book.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable