refactor(core): Unify components and adopt standard tooling
This commit performs several key refactorings within the `core`-module to improve consistency, stability, and adhere to industry best practices.
1. **Unify `Result` Type:**
Removed the specialized `Result<T>` class from `core-utils`. The entire system will now exclusively use the more flexible and type-safe `Result<T, E>` from `core-domain`. This allows for explicit, non-exception-based error handling for business logic.
2. **Adopt Flyway for Database Migrations:**
Replaced the custom `DatabaseMigrator.kt` implementation with the industry-standard tool Flyway. The `DatabaseFactory` now triggers Flyway migrations on application startup. This provides more robust, transactional, and feature-rich schema management.
3. **Cleanup and Housekeeping:**
- Removed obsolete test files related to the old migrator.
- Ensured all components align with the new unified patterns.
BREAKING CHANGE: The `at.mocode.core.utils.error.Result` class has been removed. All modules must be updated to use the `at.mocode.core.domain.error.Result` type. The custom migrator is no longer available.
Closes #ISSUE_NUMBER_FOR_REFACTORING
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package at.mocode.masterdata.api
|
||||
|
||||
import at.mocode.core.domain.model.ApiResponse
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.statuspages.*
|
||||
import io.ktor.server.response.*
|
||||
|
||||
// Eine einfache, eigene Exception, um "Nicht gefunden"-Fälle klarer zu machen.
|
||||
class NotFoundException(message: String) : RuntimeException(message)
|
||||
|
||||
fun Application.configureStatusPages() {
|
||||
install(StatusPages) {
|
||||
|
||||
// Regel 1: Fange alle "IllegalArgumentException" ab.
|
||||
// Das passiert bei ungültigen Eingaben, z.B. ein falsches UUID-Format.
|
||||
exception<IllegalArgumentException> { call, cause ->
|
||||
log.warn("Bad Request: ${cause.message}")
|
||||
val errorResponse = ApiResponse<Unit>(
|
||||
message = cause.message ?: "Invalid input provided.",
|
||||
errors = listOf("BAD_REQUEST")
|
||||
)
|
||||
call.respond(HttpStatusCode.BadRequest, errorResponse)
|
||||
}
|
||||
|
||||
// Regel 2: Fange unsere eigene "NotFoundException" ab.
|
||||
// Diese werfen wir, wenn eine Entität nicht in der DB gefunden wurde.
|
||||
exception<NotFoundException> { call, cause ->
|
||||
log.info("Resource not found: ${cause.message}")
|
||||
val errorResponse = ApiResponse<Unit>(
|
||||
message = cause.message ?: "The requested resource was not found.",
|
||||
errors = listOf("NOT_FOUND")
|
||||
)
|
||||
call.respond(HttpStatusCode.NotFound, errorResponse)
|
||||
}
|
||||
|
||||
// Regel 3: Fange alle anderen, unerwarteten Fehler ab.
|
||||
// Das ist unser Sicherheitsnetz für alles, was wir nicht vorhergesehen haben.
|
||||
exception<Throwable> { call, cause ->
|
||||
log.error("Internal Server Error", cause) // Logge den kompletten Stacktrace
|
||||
val errorResponse = ApiResponse<Unit>(
|
||||
message = "An unexpected internal server error occurred.",
|
||||
errors = listOf("INTERNAL_SERVER_ERROR")
|
||||
)
|
||||
call.respond(HttpStatusCode.InternalServerError, errorResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -91,7 +91,7 @@ class AltersklasseController(
|
||||
} catch (_: Exception) {
|
||||
return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
ApiResponse.error<List<AltersklasseDto>>("Invalid sparte parameter: $it")
|
||||
ApiResponse<List<AltersklasseDto>>("Invalid sparte parameter: $it")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class AltersklasseController(
|
||||
} else {
|
||||
return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
ApiResponse.error<List<AltersklasseDto>>("Invalid geschlecht parameter. Must be 'M' or 'W'")
|
||||
ApiResponse<List<AltersklasseDto>>("Invalid geschlecht parameter. Must be 'M' or 'W'")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user