You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.3 KiB

3 years ago
  1. package wow.doge.http4sdemo
  2. import cats.effect.Sync
  3. import cats.implicits._
  4. import fs2.interop.reactivestreams._
  5. import io.circe.Codec
  6. import io.circe.generic.semiauto._
  7. import monix.bio.Task
  8. import monix.reactive.Observable
  9. import org.http4s.HttpRoutes
  10. import org.http4s.dsl.Http4sDsl
  11. import slick.jdbc.JdbcBackend.DatabaseDef
  12. import slick.jdbc.JdbcProfile
  13. import wow.doge.http4sdemo.dto.Book
  14. import wow.doge.http4sdemo.dto.BookUpdate
  15. import wow.doge.http4sdemo.dto.NewBook
  16. import wow.doge.http4sdemo.services.LibraryService
  17. import wow.doge.http4sdemo.slickcodegen.Tables._
  18. object Http4sdemoRoutes {
  19. def jokeRoutes[F[_]: Sync](J: Jokes[F]): HttpRoutes[F] = {
  20. val dsl = Http4sDsl[F]
  21. import dsl._
  22. HttpRoutes.of[F] { case GET -> Root / "joke" =>
  23. for {
  24. joke <- J.get
  25. resp <- Ok(joke)
  26. } yield resp
  27. }
  28. }
  29. def helloWorldRoutes[F[_]: Sync](H: HelloWorld[F]): HttpRoutes[F] = {
  30. val dsl = new Http4sDsl[F] {}
  31. import dsl._
  32. HttpRoutes.of[F] { case GET -> Root / "hello" / name =>
  33. for {
  34. greeting <- H.hello(HelloWorld.Name(name))
  35. resp <- Ok(greeting)
  36. r2 <- BadRequest("Bad request")
  37. } yield r2
  38. }
  39. }
  40. def userRoutes(userService: UserService): HttpRoutes[Task] = {
  41. val dsl = Http4sDsl[Task]
  42. import dsl._
  43. import org.http4s.circe.CirceEntityCodec._
  44. HttpRoutes.of[Task] { case GET -> Root / "users" =>
  45. Task.deferAction(implicit s =>
  46. for {
  47. _ <- Task.unit
  48. users = userService.users.toReactivePublisher.toStream[Task]
  49. res <- Ok(users)
  50. } yield res
  51. )
  52. }
  53. }
  54. def libraryRoutes(libraryService: LibraryService): HttpRoutes[Task] = {
  55. val dsl = Http4sDsl[Task]
  56. import dsl._
  57. HttpRoutes.of[Task] {
  58. case GET -> Root / "api" / "get" / "books" =>
  59. import org.http4s.circe.streamJsonArrayEncoder
  60. import io.circe.syntax._
  61. Task.deferAction(implicit s =>
  62. for {
  63. books <- Task.pure(
  64. libraryService.getBooks.toReactivePublisher
  65. .toStream[Task]
  66. )
  67. res <- Ok(books.map(_.asJson))
  68. } yield res
  69. )
  70. case GET -> Root / "api" / "get" / "book" / IntVar(id) =>
  71. // import org.http4s.circe.CirceEntityCodec._
  72. import org.http4s.circe.jsonEncoder
  73. import io.circe.syntax._
  74. for {
  75. bookJson <- libraryService.getBookById(id).map(_.asJson)
  76. res <- Ok(bookJson)
  77. } yield res
  78. case req @ POST -> Root / "api" / "post" / "book" =>
  79. import org.http4s.circe.CirceEntityCodec._
  80. for {
  81. newBook <- req.as[NewBook]
  82. book <- libraryService.insertBook(newBook)
  83. res <- Created(book)
  84. } yield res
  85. case req @ PATCH -> Root / "api" / "update" / "book" / IntVar(id) =>
  86. import org.http4s.circe.CirceEntityCodec._
  87. for {
  88. updateData <- req.as[BookUpdate]
  89. _ <- libraryService
  90. .updateBook(id, updateData)
  91. .void
  92. .onErrorHandleWith(ex =>
  93. Task(println(s"Handled -> ${ex.getMessage}"))
  94. )
  95. // .mapError(e => new Exception(e))
  96. res <- Ok()
  97. } yield res
  98. case req @ DELETE -> Root / "api" / "delete" / "book" / IntVar(id) =>
  99. for {
  100. _ <- libraryService.deleteBook(id)
  101. res <- Ok()
  102. } yield res
  103. case req @ POST -> Root / "api" / "post" / "books" / "read" =>
  104. import org.http4s.circe.CirceEntityCodec.circeEntityDecoder
  105. for {
  106. newBook <- req.as[List[Book]]
  107. // book <- libraryService.insertBook(newBook)
  108. res <- Ok("blah")
  109. } yield res
  110. }
  111. }
  112. }
  113. case class User(id: String, email: String)
  114. object User {
  115. val tupled = (this.apply _).tupled
  116. // implicit val decoder: Decoder[User] = deriveDecoder
  117. // implicit def entityDecoder[F[_]: Sync]: EntityDecoder[F, User] =
  118. // jsonOf
  119. // implicit val encoder: Encoder[User] = deriveEncoder
  120. // implicit def entityEncoder[F[_]: Applicative]: EntityEncoder[F, User] =
  121. // jsonEncoderOf
  122. implicit val codec: Codec[User] = deriveCodec
  123. }
  124. class UserService(profile: JdbcProfile, db: DatabaseDef) {
  125. import profile.api._
  126. def users: Observable[User] =
  127. Observable.fromReactivePublisher(
  128. db.stream(Users.map(u => (u.id, u.email).mapTo[User]).result)
  129. )
  130. }