From 506a6095e160e4659714fd5de8dc1fd1ff0d258b Mon Sep 17 00:00:00 2001 From: Alan Brault Date: Mon, 2 Mar 2026 08:08:20 -0500 Subject: [PATCH] refactor: architecture Signed-off-by: Alan Brault --- .../kotlinapi/controller/HealthController.kt | 20 ++----------- .../kotlinapi/domain/port/HealthIndicator.kt | 7 +++++ .../kotlinapi/domain/service/HealthService.kt | 28 +++++++++++++++++-- .../health/MongoHealthService.kt | 4 +-- 4 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 src/main/kotlin/io/visus/demos/kotlinapi/domain/port/HealthIndicator.kt diff --git a/src/main/kotlin/io/visus/demos/kotlinapi/controller/HealthController.kt b/src/main/kotlin/io/visus/demos/kotlinapi/controller/HealthController.kt index df0c1b1..028f61a 100644 --- a/src/main/kotlin/io/visus/demos/kotlinapi/controller/HealthController.kt +++ b/src/main/kotlin/io/visus/demos/kotlinapi/controller/HealthController.kt @@ -6,11 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import io.visus.demos.kotlinapi.api.dto.HealthResponse -import io.visus.demos.kotlinapi.api.mappers.HealthResponseMapper -import io.visus.demos.kotlinapi.domain.model.HealthStatus -import io.visus.demos.kotlinapi.domain.model.Status import io.visus.demos.kotlinapi.domain.service.HealthService -import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -19,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController @RestController @Tag(name = "Health", description = "Health check endpoints") class HealthController( - private val healthCheckServices: List, + private val healthCheckService: HealthService, ) { @GetMapping("/health", produces = [MediaType.APPLICATION_JSON_VALUE]) @Operation( @@ -48,17 +44,5 @@ class HealthController( ), ], ) - fun health(): ResponseEntity { - val componentHealths = healthCheckServices.map { it.check() } - val healthStatus = HealthStatus.fromComponents(componentHealths) - val response = HealthResponseMapper.map(healthStatus) - - val httpStatus = - when (healthStatus.status) { - Status.UP -> HttpStatus.OK - Status.DOWN, Status.DEGRADED -> HttpStatus.SERVICE_UNAVAILABLE - } - - return ResponseEntity.status(httpStatus).body(response) - } + fun health(): ResponseEntity = healthCheckService.check() } diff --git a/src/main/kotlin/io/visus/demos/kotlinapi/domain/port/HealthIndicator.kt b/src/main/kotlin/io/visus/demos/kotlinapi/domain/port/HealthIndicator.kt new file mode 100644 index 0000000..64d9481 --- /dev/null +++ b/src/main/kotlin/io/visus/demos/kotlinapi/domain/port/HealthIndicator.kt @@ -0,0 +1,7 @@ +package io.visus.demos.kotlinapi.domain.port + +import io.visus.demos.kotlinapi.domain.model.ComponentHealth + +interface HealthIndicator { + fun check(): ComponentHealth +} diff --git a/src/main/kotlin/io/visus/demos/kotlinapi/domain/service/HealthService.kt b/src/main/kotlin/io/visus/demos/kotlinapi/domain/service/HealthService.kt index 4d2140c..4fd259f 100644 --- a/src/main/kotlin/io/visus/demos/kotlinapi/domain/service/HealthService.kt +++ b/src/main/kotlin/io/visus/demos/kotlinapi/domain/service/HealthService.kt @@ -1,7 +1,29 @@ package io.visus.demos.kotlinapi.domain.service -import io.visus.demos.kotlinapi.domain.model.ComponentHealth +import io.visus.demos.kotlinapi.api.dto.HealthResponse +import io.visus.demos.kotlinapi.api.mappers.HealthResponseMapper +import io.visus.demos.kotlinapi.domain.port.HealthIndicator +import io.visus.demos.kotlinapi.domain.model.HealthStatus +import io.visus.demos.kotlinapi.domain.model.Status +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Service -interface HealthService { - fun check(): ComponentHealth +@Service +class HealthService( + private val healthIndicators: List, +) { + fun check(): ResponseEntity { + val componentHealths = healthIndicators.map { it.check() } + val healthStatus = HealthStatus.fromComponents(componentHealths) + val response = HealthResponseMapper.map(healthStatus) + + val httpStatus = + when (healthStatus.status) { + Status.UP -> HttpStatus.OK + Status.DOWN, Status.DEGRADED -> HttpStatus.SERVICE_UNAVAILABLE + } + + return ResponseEntity.status(httpStatus).body(response) + } } diff --git a/src/main/kotlin/io/visus/demos/kotlinapi/infrastructure/health/MongoHealthService.kt b/src/main/kotlin/io/visus/demos/kotlinapi/infrastructure/health/MongoHealthService.kt index d08c7d4..e5a62d2 100644 --- a/src/main/kotlin/io/visus/demos/kotlinapi/infrastructure/health/MongoHealthService.kt +++ b/src/main/kotlin/io/visus/demos/kotlinapi/infrastructure/health/MongoHealthService.kt @@ -3,14 +3,14 @@ package io.visus.demos.kotlinapi.infrastructure.health import com.mongodb.client.MongoClient import io.visus.demos.kotlinapi.domain.model.ComponentHealth import io.visus.demos.kotlinapi.domain.model.ComponentStatus -import io.visus.demos.kotlinapi.domain.service.HealthService +import io.visus.demos.kotlinapi.domain.port.HealthIndicator import org.bson.Document import org.springframework.stereotype.Service @Service class MongoHealthService( private val mongoClient: MongoClient, -) : HealthService { +) : HealthIndicator { override fun check(): ComponentHealth = try { val command = Document("ping", 1)