Skip to content

Commit

Permalink
Merge pull request #1 from mmvpm/stub
Browse files Browse the repository at this point in the history
Add stub
  • Loading branch information
bogdanspbm authored Mar 6, 2024
2 parents 2862f23 + 0750e8f commit e1d78ae
Show file tree
Hide file tree
Showing 33 changed files with 679 additions and 4 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/scala-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Build and run tests

on:
push:
branches:
- '*'
pull_request:
branches:
- '*'

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: 'sbt'
- name: Build
run: sbt scalafmtSbtCheck scalafmtCheckAll compile
- name: Run stub tests
run: sbt stub/test
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.class
*.log

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.idea
target
project/target
.bsp
17 changes: 17 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version = 3.0.3

runner.dialect = scala213

style = default

maxColumn = 120

trailingCommas = never

rewrite.rules = [
AvoidInfix
RedundantBraces
RedundantParens
AsciiSortImports
PreferCurlyFors
]
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# OffersService
# OffersService

## How to launch

```bash
docker compose start
```

```bash
sbt "project stub" run
```
137 changes: 137 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
addCompilerPlugin(("org.typelevel" % "kind-projector" % "0.13.2").cross(CrossVersion.full))

ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.13.12"

val catsVersion = "2.9.0"
val catsEffect3 = "3.4.8"
val circeVersion = "0.14.6"
val tapirVersion = "1.7.6"
val tapirCirce = "1.9.5"
val http4sVersion = "0.23.23"
val logbackVersion = "1.4.11"
val apacheCommonsVersion = "1.16.0"
val pureConfigVersion = "0.17.4"
val flywayVersion = "9.16.0"
val doobieVersion = "1.0.0-RC2"
val quillVersion = "4.6.0"
val redisVersion = "3.42"
val scrapperVersion = "3.0.0"
val sttpClientVersion = "3.9.0"
val catsRetryVersion = "3.1.0"
val catsBackendVersion = "3.8.13"

val testVersion = "1.4.0"
val scalatestVersion = "3.2.17"
val mockitoVersion = "3.2.16.0"
val wireMockVersion = "3.0.0"
val catsTestingVersion = "1.4.0"
val testcontainersVersion = "0.40.15"
val testcontainersRedis = "1.3.2"
val testcontainersPostgresqlVersion = "0.40.12"

val cats = Seq(
"org.typelevel" %% "cats-core" % catsVersion,
"org.typelevel" %% "cats-effect" % catsEffect3
)

val circe = Seq(
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion
)

val pureconfig = Seq(
"com.github.pureconfig" %% "pureconfig" % pureConfigVersion
)

val redis = Seq(
"net.debasishg" %% "redisclient" % redisVersion
)

val tapir = Seq(
"com.softwaremill.sttp.tapir" %% "tapir-http4s-server" % tapirVersion,
"com.softwaremill.sttp.tapir" %% "tapir-swagger-ui-bundle" % tapirVersion,
"com.softwaremill.sttp.tapir" %% "tapir-json-circe" % tapirCirce
)

val http4s = Seq(
"org.http4s" %% "http4s-ember-server" % http4sVersion
)

val logback = Seq(
"ch.qos.logback" % "logback-classic" % logbackVersion
)

val apacheCommons = Seq(
"commons-codec" % "commons-codec" % apacheCommonsVersion
)

val databases = Seq(
"org.tpolecat" %% "doobie-core" % doobieVersion,
"org.tpolecat" %% "doobie-postgres" % doobieVersion,
"org.tpolecat" %% "doobie-hikari" % doobieVersion,
"org.flywaydb" % "flyway-core" % flywayVersion
)

val sttpClient = Seq(
"com.softwaremill.sttp.client3" %% "core" % sttpClientVersion,
"com.softwaremill.sttp.client3" %% "circe" % sttpClientVersion,
"com.softwaremill.sttp.client3" %% "async-http-client-backend-cats" % catsBackendVersion
)

val catsRetry = Seq(
"com.github.cb372" %% "cats-retry" % catsRetryVersion
)

val scrapper = Seq(
"net.ruippeixotog" %% "scala-scraper" % scrapperVersion
)

val testcontainers = Seq(
"com.redislabs.testcontainers" % "testcontainers-redis" % testcontainersRedis,
"com.dimafeng" %% "testcontainers-scala-scalatest" % testcontainersVersion,
"com.dimafeng" %% "testcontainers-scala-postgresql" % testcontainersPostgresqlVersion
)

val scalatest = Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
)

val mockito = Seq(
"org.scalatestplus" %% "mockito-4-11" % mockitoVersion % Test
)

val catsTesting = Seq(
"org.typelevel" %% "cats-effect-testing-scalatest" % catsTestingVersion % Test
)

val tapirStubServer = Seq(
"com.softwaremill.sttp.tapir" %% "tapir-sttp-stub-server" % tapirVersion % Test
)

lazy val common = (project in file("common"))
.settings(
name := "common"
)

lazy val stub = (project in file("stub"))
.dependsOn(common)
.settings(
name := "stub",
libraryDependencies ++= Seq(
cats,
logback,
pureconfig,
tapir,
http4s,
databases
).flatten
)

lazy val root = (project in file("."))
.settings(
name := "OffersService"
)
.aggregate(common, stub)
3 changes: 3 additions & 0 deletions common/src/main/scala/com/github/mmvpm/model/Stub.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.mmvpm.model

case class Stub(id: StubID, data: String)
7 changes: 7 additions & 0 deletions common/src/main/scala/com/github/mmvpm/model/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.mmvpm

import java.util.UUID

package object model {
type StubID = UUID
}
17 changes: 17 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: '3.8'

services:
db:
image: postgres:14.1-alpine
restart: always
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
- '5432:5432'
volumes:
- db:/var/lib/postgresql/data

volumes:
db:
driver: local
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.8.3
6 changes: 6 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.1.0")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.9")
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1")
addCompilerPlugin(("org.scalamacros" % "paradise" % "2.1.1").cross(CrossVersion.full))
addCompilerPlugin(("org.typelevel" % "kind-projector" % "0.13.2").cross(CrossVersion.full))
11 changes: 11 additions & 0 deletions stub/src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
server {
host = localhost
port = 8080
}

postgresql {
url = "jdbc:postgresql://localhost:5432/postgres"
user = "postgres"
password = "postgres"
pool-size = 2
}
5 changes: 5 additions & 0 deletions stub/src/main/resources/db.migration/V1__stubs.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
create table stubs
(
id uuid primary key,
data text
)
7 changes: 7 additions & 0 deletions stub/src/main/scala/com/github/mmvpm/stub/Config.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.mmvpm.stub

case class Config(server: ServerConfig, postgresql: PostgresqlConfig)

case class ServerConfig(host: String, port: Int)

case class PostgresqlConfig(url: String, user: String, password: String, poolSize: Int)
75 changes: 75 additions & 0 deletions stub/src/main/scala/com/github/mmvpm/stub/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.github.mmvpm.stub

import cats.data.EitherT
import cats.effect.{ExitCode, IO, IOApp}
import cats.implicits.catsSyntaxApplicativeError
import com.comcast.ip4s.{Host, Port}
import com.github.mmvpm.stub.api._
import com.github.mmvpm.stub.dao._
import com.github.mmvpm.stub.service._
import com.github.mmvpm.stub.util.FlywayMigration
import com.github.mmvpm.stub.util.Postgresql.makeTransactor
import doobie.Transactor
import org.http4s.ember.server.EmberServerBuilder
import org.http4s.server.Router
import org.http4s.HttpRoutes
import pureconfig.ConfigSource
import pureconfig.generic.auto._
import sttp.tapir.server.http4s.Http4sServerInterpreter
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.swagger.bundle.SwaggerInterpreter

object Main extends IOApp {

override def run(args: List[String]): IO[ExitCode] = {
val config = ConfigSource.default.loadOrThrow[Config]
makeTransactor[IO](config.postgresql).use(runServer(config)(_))
}

private def runServer(config: Config)(implicit xa: Transactor[IO]): IO[ExitCode] =
for {
_ <- IO.pure(0)

pingHandler: PingHandler[IO] = new PingHandler[IO]

stubDao: StubDao[IO] = new StubDaoPostgresql[IO]
stubService: StubService[IO] = new StubServiceImpl[IO](stubDao)
stubHandler: StubHandler[IO] = new StubHandler[IO](stubService)

handlers = List(pingHandler, stubHandler)
endpoints <- IO.delay(handlers.flatMap(_.endpoints))
routes = Http4sServerInterpreter[IO].toRoutes(swaggerBy(endpoints) ++ endpoints)
server <- serverBuilder(config, routes).value.rethrow

_ <- FlywayMigration.migrate[IO](config.postgresql)

_ <- server.build.use { server =>
val (host, port) = (server.address.getHostName, server.address.getPort)
IO.println(s"SwaggerUI: http://$host:$port/docs") >> IO.never
}
} yield ExitCode.Success

private def serverBuilder(config: Config, routes: HttpRoutes[IO]): EitherT[IO, Throwable, EmberServerBuilder[IO]] =
for {
host <- parseHost(config.server.host)
port <- parsePort(config.server.port)
builder <- IO.delay {
EmberServerBuilder
.default[IO]
.withHost(host)
.withPort(port)
.withHttpApp(
Router("/" -> routes).orNotFound
)
}.attemptT
} yield builder

private def parseHost(host: String): EitherT[IO, Throwable, Host] =
EitherT.fromOption[IO](Host.fromString(host), new IllegalArgumentException(s"incorrect host '$host'"))

private def parsePort(port: Int): EitherT[IO, Throwable, Port] =
EitherT.fromOption[IO](Port.fromInt(port), new IllegalArgumentException(s"incorrect port '$port'"))

private def swaggerBy[A](endpoints: List[ServerEndpoint[A, IO]]): List[ServerEndpoint[A, IO]] =
SwaggerInterpreter().fromServerEndpoints[IO](endpoints, "offers-service", "1.0.0")
}
7 changes: 7 additions & 0 deletions stub/src/main/scala/com/github/mmvpm/stub/api/Handler.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.mmvpm.stub.api

import sttp.tapir.server.ServerEndpoint

trait Handler[F[_]] {
def endpoints: List[ServerEndpoint[Any, F]]
}
17 changes: 17 additions & 0 deletions stub/src/main/scala/com/github/mmvpm/stub/api/PingHandler.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.mmvpm.stub.api
import cats.Applicative
import sttp.tapir._
import sttp.tapir.server.ServerEndpoint

class PingHandler[F[_]: Applicative] extends Handler[F] {

private val ping: ServerEndpoint[Any, F] =
endpoint.get
.summary("Ping")
.in("api" / "v1" / "ping")
.out(stringBody)
.serverLogic(_ => Applicative[F].pure(Right("pong")))

override def endpoints: List[ServerEndpoint[Any, F]] =
List(ping).map(_.withTag("util"))
}
Loading

0 comments on commit e1d78ae

Please sign in to comment.