Skip to content

Commit

Permalink
Merge pull request #7 from everpeace/no-response-body-by-default
Browse files Browse the repository at this point in the history
response body become empty json object by default for performance.
  • Loading branch information
everpeace authored Oct 27, 2017
2 parents f826166 + ee19d36 commit 7662716
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 16 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ All you need to give is just health check function returning cats `ValidationNel

val response = Http().singleRequest(HttpRequest(uri = "http://localhost:8888/health"))

// response body would be an json object similar to below.
// status code is 200(OK) if healthy, 500(Internal Server Error) if unhealthy.
// response body is empty by default for performance.
// pass '?full=true' query parameter to see full check result as json. it would be similar to below.
// Please see com.github.everpeace.healthchecks.HealthRoutesTest for various response patterns.
// {
// "status": "healthy",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ package com.github.everpeace.healthchecks.route

import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{PathMatchers, Route}
import akka.http.scaladsl.server.directives.PathDirectives
import akka.http.scaladsl.server.{PathMatchers, Route}
import cats.data.Validated.{Invalid, Valid}
import com.github.everpeace.healthchecks.{HealthCheck, HealthCheckResult}
import de.heikoseeberger.akkahttpcirce.CirceSupport._
import io.circe.JsonObject
import io.circe.generic.JsonCodec
import io.circe.generic.auto._

Expand All @@ -48,10 +49,13 @@ object HealthCheckRoutes extends DecorateAsScala {
severity: String,
status: String,
messages: List[String])

@JsonCodec case class ResponseJson(status: String, check_results: List[HealthCheckResultJson])

private def status(s: Boolean) = if (s) "healthy" else "unhealthy"
private def status(s: Boolean) = if (s) "healthy" else "unhealthy"

private def statusCode(s: Boolean) = if (s) OK else InternalServerError

private def toResultJson(check: HealthCheck, result: HealthCheckResult) =
HealthCheckResultJson(
check.name,
Expand Down Expand Up @@ -83,21 +87,32 @@ object HealthCheckRoutes extends DecorateAsScala {
val rootSlashRemoved =
if (path.startsWith("/")) path.substring(1) else path
PathDirectives.path(PathMatchers.separateOnSlashes(rootSlashRemoved)) {
get {
complete {
Future
.traverse(checks.toList) { c =>
c.run().map(c -> _)
parameter("full" ? false) { full =>
get {
def isHealthy(checkAndResults: List[(HealthCheck, HealthCheckResult)]) =
checkAndResults.forall(cr => cr._2.isValid || (!cr._1.severity.isFatal))
val checkAndResultsFuture = Future.traverse(checks.toList) { c =>
c.run().map(c -> _)
}
if (full) {
complete {
checkAndResultsFuture.map { checkAndResults =>
val healthy = isHealthy(checkAndResults)
statusCode(healthy) -> ResponseJson(
status(healthy),
checkAndResults.map {
case (check, result) => toResultJson(check, result)
}
)
}
}
.map { checkAndResults =>
val healthy = checkAndResults.forall(cr => cr._2.isValid || (!cr._1.severity.isFatal))
statusCode(healthy) -> ResponseJson(
status(healthy),
checkAndResults.map {
case (check, result) => toResultJson(check, result)
}
)
} else {
complete {
checkAndResultsFuture.map { checkAndResults =>
statusCode(isHealthy(checkAndResults)) -> JsonObject.empty
}
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ class HealthRoutesTest
val ok2 = healthCheck("test2")(healthy)

Get("/health") ~> HealthCheckRoutes.health(ok1, ok2) ~> check {
status shouldEqual OK
responseAs[String] shouldEqual "{}"
}

Get("/health?full=true") ~> HealthCheckRoutes.health(ok1, ok2) ~> check {
status shouldEqual OK
responseAs[String] shouldEqual
"""
Expand All @@ -81,6 +86,11 @@ class HealthRoutesTest
healthCheck("test2", Severity.NonFatal)(unhealthy("error"))

Get("/health") ~> HealthCheckRoutes.health(ok1, failedButNonFatal) ~> check {
status shouldEqual OK
responseAs[String] shouldEqual "{}"
}

Get("/health?full=true") ~> HealthCheckRoutes.health(ok1, failedButNonFatal) ~> check {
status shouldEqual OK
responseAs[String] shouldEqual
"""
Expand All @@ -103,6 +113,11 @@ class HealthRoutesTest
val failedFatal = healthCheck("test3")(throw new Exception("exception"))

Get("/health") ~> HealthCheckRoutes.health(ok, failedButNonFatal, failedFatal) ~> check {
status shouldEqual InternalServerError
responseAs[String] shouldEqual "{}"
}

Get("/health?full=true") ~> HealthCheckRoutes.health(ok, failedButNonFatal, failedFatal) ~> check {
status shouldEqual InternalServerError
responseAs[String] shouldEqual
"""
Expand Down

0 comments on commit 7662716

Please sign in to comment.