Skip to content

Commit

Permalink
Feat: add DistributedCacheService & tests (#13)
Browse files Browse the repository at this point in the history
* feat(cache): add distributed cache service & add tests

* feat(docs): add documentation

* feat(app): split resource creation
  • Loading branch information
sobakavosne authored Nov 21, 2024
1 parent 30d9191 commit a977d26
Show file tree
Hide file tree
Showing 35 changed files with 1,545 additions and 280 deletions.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ enablePlugins(DockerPlugin, JavaAppPackaging)
Docker / packageName := "chemist-flow"
Docker / dockerExposedPorts := Seq(8081)

Test / scalaSource := baseDirectory.value / "src" / "test" / "scala"
Test / scalaSource := baseDirectory.value / "src" / "test" / "scala"
Test / parallelExecution := false

lazy val root = (project in file("."))
.settings(
Expand All @@ -35,6 +36,7 @@ lazy val root = (project in file("."))
akkaCluster.cross(CrossVersion.for3Use2_13),
akkaDistributedData.cross(CrossVersion.for3Use2_13),
akkaActor.cross(CrossVersion.for3Use2_13),
akkaTestTyped.cross(CrossVersion.for3Use2_13)
// akkaTest.cross(CrossVersion.for3Use2_13),
// docker
)
Expand Down
36 changes: 18 additions & 18 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ object Dependencies {
lazy val http4sVersion = "0.23.29"
lazy val log4catsVersion = "2.7.0"

lazy val akkaActor = "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion
lazy val akkaStream = "com.typesafe.akka" %% "akka-stream-typed" % akkaVersion
lazy val akkaCluster = "com.typesafe.akka" %% "akka-cluster-typed" % akkaVersion
lazy val akkaDistributedData = "com.typesafe.akka" %% "akka-distributed-data" % akkaVersion
lazy val scalaLogging = "ch.qos.logback" % "logback-classic" % scalaLogVersion
lazy val log4cats = "org.typelevel" %% "log4cats-core" % log4catsVersion
lazy val docker = "com.spotify" % "docker-client" % dockerVersion
lazy val catsEffect = "org.typelevel" %% "cats-effect" % catsEffectVersion
lazy val circeCore = "io.circe" %% "circe-core" % circeVersion
lazy val circeGeneric = "io.circe" %% "circe-generic" % circeVersion
lazy val circeParser = "io.circe" %% "circe-parser" % circeVersion
lazy val pureconfig = "com.github.pureconfig" %% "pureconfig" % pureconfigVersion
lazy val http4sEmberClient = "org.http4s" %% "http4s-ember-client" % http4sVersion
lazy val http4sEmberServer = "org.http4s" %% "http4s-ember-server" % http4sVersion
lazy val http4sCirce = "org.http4s" %% "http4s-circe" % http4sVersion
lazy val http4sDSL = "org.http4s" %% "http4s-dsl" % http4sVersion
lazy val akkaTest = "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test
lazy val scalaTest = "org.scalatest" %% "scalatest" % scalaTestVersion % Test
lazy val akkaActor = "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion
lazy val akkaStream = "com.typesafe.akka" %% "akka-stream-typed" % akkaVersion
lazy val akkaCluster = "com.typesafe.akka" %% "akka-cluster-typed" % akkaVersion
lazy val akkaDistributedData = "com.typesafe.akka" %% "akka-distributed-data" % akkaVersion
lazy val scalaLogging = "ch.qos.logback" % "logback-classic" % scalaLogVersion
lazy val log4cats = "org.typelevel" %% "log4cats-core" % log4catsVersion
lazy val docker = "com.spotify" % "docker-client" % dockerVersion
lazy val catsEffect = "org.typelevel" %% "cats-effect" % catsEffectVersion
lazy val circeCore = "io.circe" %% "circe-core" % circeVersion
lazy val circeGeneric = "io.circe" %% "circe-generic" % circeVersion
lazy val circeParser = "io.circe" %% "circe-parser" % circeVersion
lazy val pureconfig = "com.github.pureconfig" %% "pureconfig" % pureconfigVersion
lazy val http4sEmberClient = "org.http4s" %% "http4s-ember-client" % http4sVersion
lazy val http4sEmberServer = "org.http4s" %% "http4s-ember-server" % http4sVersion
lazy val http4sCirce = "org.http4s" %% "http4s-circe" % http4sVersion
lazy val http4sDSL = "org.http4s" %% "http4s-dsl" % http4sVersion
lazy val akkaTestTyped = "com.typesafe.akka" %% "akka-actor-testkit-typed" % akkaVersion % Test
lazy val scalaTest = "org.scalatest" %% "scalatest" % scalaTestVersion % Test
}
16 changes: 16 additions & 0 deletions src/main/scala/api/ErrorHandler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@ import io.circe.syntax._
import io.circe.generic.auto._
import org.http4s.circe.CirceEntityEncoder._

/**
* Represents an error response returned by the server.
*
* @param error
* The type of error (e.g., "NotFound", "BadRequest").
* @param message
* A descriptive message about the error.
*/
final case class ErrorResponse(error: String, message: String)

object ErrorHandler {

/**
* Wraps the provided HTTP routes with error handling logic.
*
* @param routes
* The `HttpRoutes[IO]` to be wrapped with error handling.
* @return
* A new `HttpRoutes[IO]` that handles errors and returns appropriate HTTP responses with JSON error messages.
*/
def apply(routes: HttpRoutes[IO]): HttpRoutes[IO] = HttpRoutes.of[IO] { request =>
routes(request).getOrElseF(
IO(Response(Status.NotFound).withEntity(ErrorResponse(
Expand Down
17 changes: 17 additions & 0 deletions src/main/scala/api/ServerBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,27 @@ import org.http4s.server.Server
import org.http4s.ember.server.EmberServerBuilder
import org.http4s.HttpRoutes

/**
* A class responsible for building and starting an HTTP server.
*
* @param routes
* The HTTP routes to be served by the server.
*/
class ServerBuilder(
routes: HttpRoutes[IO]
) {

/**
* Starts the HTTP server with the specified host and port configuration.
*
* @param host
* The host address on which the server will listen.
* @param port
* The port number on which the server will listen.
* @return
* A `Resource[IO, Server]` that represents the running HTTP server. The server will be properly managed and
* terminated when the `Resource` is released.
*/
def startServer(
host: Host,
port: Port
Expand Down
16 changes: 16 additions & 0 deletions src/main/scala/api/endpoints/flow/ReaktoroEndpoints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,26 @@ object ComputePropsRequest {
implicit val encoder: Encoder[ComputePropsRequest] = deriveEncoder
}

/**
* Defines the HTTP routes for interacting with the ReaktoroService.
*
* @param reaktoroService
* The service handling system property computations.
*/
class ReaktoroEndpoints(
reaktoroService: ReaktoroService[IO]
) {

/**
* HTTP POST route for computing system properties for a reaction.
*
* Endpoint: `/api/system/properties`
*
* @param req
* The HTTP request containing a `ComputePropsRequest` object in the body.
* @return
* A JSON response containing the computed system properties or an error message.
*/
private val computeSystemPropsForReactionRoute: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ POST -> Root / "system" / "properties" =>
req.as[ComputePropsRequest].flatMap {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,27 @@ import core.services.preprocessor.{MechanismService, ReactionService}
import core.domain.preprocessor.{MechanismDetails, Reaction, ReactionDetails}
import core.errors.http.preprocessor.ReactionError

/**
* Defines the HTTP routes for handling reactions and mechanisms in the preprocessor.
*
* @param reactionService
* The service that handles reactions-related operations.
* @param mechanismService
* The service that handles mechanisms-related operations.
*/
class PreprocessorEndpoints(
reactionService: ReactionService[IO],
mechanismService: MechanismService[IO]
) {

/**
* HTTP GET route for fetching a reaction by its ID.
*
* @param id
* The ID of the reaction to fetch.
* @return
* A `ReactionDetails` object in JSON format or an appropriate error response.
*/
private val getReactionRoute: HttpRoutes[IO] = HttpRoutes.of[IO] {
case GET -> Root / "reaction" / id =>
validateId(id) match {
Expand All @@ -35,6 +51,14 @@ class PreprocessorEndpoints(
}
}

/**
* HTTP POST route for creating a new reaction.
*
* @param req
* The HTTP request containing the `Reaction` object in the body.
* @return
* The created `Reaction` object in JSON format or an appropriate error response.
*/
private val postReactionRoute: HttpRoutes[IO] = HttpRoutes.of[IO] {
case req @ POST -> Root / "reaction" =>
req.as[Reaction].flatMap { reaction =>
Expand All @@ -47,6 +71,14 @@ class PreprocessorEndpoints(
}
}

/**
* HTTP DELETE route for deleting a reaction by its ID.
*
* @param id
* The ID of the reaction to delete.
* @return
* HTTP 204 No Content on success, or an appropriate error response.
*/
private val deleteReactionRoute: HttpRoutes[IO] = HttpRoutes.of[IO] {
case DELETE -> Root / "reaction" / id =>
validateId(id) match {
Expand All @@ -59,6 +91,14 @@ class PreprocessorEndpoints(
}
}

/**
* HTTP GET route for fetching a mechanism by its ID.
*
* @param id
* The ID of the mechanism to fetch.
* @return
* A `MechanismDetails` object in JSON format or an appropriate error response.
*/
private val getMechanismRoute: HttpRoutes[IO] = HttpRoutes.of[IO] {
case GET -> Root / "mechanism" / id =>
validateId(id) match {
Expand Down
Loading

0 comments on commit a977d26

Please sign in to comment.