Advertisement
mitrakov

Http4s Server with DB and Hikari Transactor

Aug 4th, 2019
472
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 3.58 KB | None | 0 0
  1. // Main.scala:
  2. import cats.effect._
  3. import cats.implicits._
  4. import doobie.hikari.HikariTransactor
  5. import doobie.util.ExecutionContexts
  6. import fs2.Stream
  7. import org.flywaydb.core.Flyway
  8. import org.flywaydb.core.internal.jdbc.DriverDataSource
  9. import org.http4s.HttpApp
  10. import org.http4s.implicits._
  11. import org.http4s.server.Router
  12. import org.http4s.server.blaze.BlazeServerBuilder
  13. import org.http4s.server.middleware.{CORS, Logger}
  14. import org.http4s.server.staticcontent._
  15. import server.setting.{SettingRoutes, SettingService}
  16.  
  17. object Main extends IOApp {
  18.   override def run(args: List[String]): IO[ExitCode] = {
  19.     runMigrations()
  20.     val transactor: Resource[IO, HikariTransactor[IO]] = createTransactor()
  21.     transactor.use { tx =>
  22.       val db: Db[IO] = new Db(tx)
  23.       val settingService: SettingService[IO] = new SettingService(db)
  24.  
  25.       val app: HttpApp[IO] = createApp(settingService)
  26.       val loggedCorsApp: HttpApp[IO] = CORS(Logger.httpApp(logHeaders = true, logBody = true)(app))
  27.       val server: Stream[IO, ExitCode] = createServer(app = loggedCorsApp)
  28.  
  29.       server.compile.drain.as(ExitCode.Success)
  30.     }
  31.   }
  32.  
  33.   def createApp[F[_]: Effect : ContextShift](service: SettingService[F]): HttpApp[F] = {
  34.     Router("/" -> fileService[F](FileService.Config("./assets")), "/setting" -> SettingRoutes.routes[F](service)).orNotFound
  35.   }
  36.  
  37.   def createServer[F[_]: ConcurrentEffect: Timer](host: String = "0.0.0.0", port: Int = 8080, app: HttpApp[F]): Stream[F, ExitCode] = {
  38.     BlazeServerBuilder[F].bindHttp(port, host).withHttpApp(app).serve
  39.   }
  40.  
  41.   def createTransactor[F[_]: Async : ContextShift](
  42.             driver: String = "org.postgresql.Driver",
  43.             url: String = "jdbc:postgresql://localhost:5432/postgres",
  44.             user: String = "postgres",
  45.             password: String = "postgres",
  46.             connectionThreads: Int = 32
  47.           ): Resource[F, HikariTransactor[F]] = {
  48.     for {
  49.       connectEc <- ExecutionContexts.fixedThreadPool[F](connectionThreads)
  50.       transactEc <- ExecutionContexts.cachedThreadPool[F]
  51.       xa <- HikariTransactor.newHikariTransactor[F](driver, url, user, password, connectEc, transactEc)
  52.     } yield xa
  53.   }
  54.  
  55.   def runMigrations(driver: String = "org.postgresql.Driver",
  56.                     url: String = "jdbc:postgresql://localhost:5432/postgres",
  57.                     user: String = "postgres",
  58.                     password: String = "postgres"): Int = {
  59.     val source = new DriverDataSource(getClass.getClassLoader, driver, url, user, password)
  60.     Flyway.configure().dataSource(source).load().migrate()
  61.   }
  62. }
  63.  
  64.  
  65.  
  66. // Db.scala
  67. import cats.effect.Bracket
  68. import doobie.free.connection.ConnectionIO
  69. import doobie.util.transactor.Transactor
  70. import doobie.implicits._
  71.  
  72. class Db[F[_]](tx: Transactor[F])(implicit ev: Bracket[F, Throwable]) {
  73.   def run[A](program: ConnectionIO[A]): F[A] = program.transact(tx)
  74. }
  75.  
  76.  
  77.  
  78. // SettingRoutes.scala:
  79. import cats.effect._
  80. import org.http4s.HttpRoutes
  81. import org.http4s.dsl.Http4sDsl
  82.  
  83. object SettingRoutes {
  84.   def routes[F[_] : Sync](service: SettingService[F]): HttpRoutes[F] = {
  85.     val dsl = new Http4sDsl[F] {}
  86.     import dsl._
  87.     import cats.implicits._
  88.  
  89.     HttpRoutes.of[F] {
  90.       case GET -> Root / "hey" =>
  91.         for {
  92.           count <- service.getCountTest
  93.           ok <- Ok(s"Size = $count")
  94.         } yield ok
  95.     }
  96.   }
  97. }
  98.  
  99.  
  100.  
  101. // SettingService.scala:
  102. import server.Db
  103. import doobie.implicits._
  104.  
  105. class SettingService[F[_]](db: Db[F]) {
  106.   def getCountTest: F[Int] = {
  107.     db.run(sql"""SELECT COUNT(*) FROM user;""".query[Int].unique)
  108.   }
  109. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement