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.

114 lines
3.6 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package wow.doge.http4sdemo.routes
  2. import fs2.interop.reactivestreams._
  3. import io.circe.Codec
  4. import io.circe.generic.semiauto._
  5. import io.odin.Logger
  6. import monix.bio.IO
  7. import monix.bio.Task
  8. import org.http4s.HttpRoutes
  9. import org.http4s.dsl.Http4sDsl
  10. import wow.doge.http4sdemo.dto.Book
  11. import wow.doge.http4sdemo.dto.BookSearchMode
  12. import wow.doge.http4sdemo.dto.BookUpdate
  13. import wow.doge.http4sdemo.dto.NewBook
  14. import wow.doge.http4sdemo.implicits._
  15. import wow.doge.http4sdemo.services.LibraryService
  16. class LibraryRoutes(libraryService: LibraryService, logger: Logger[Task]) {
  17. val routes: HttpRoutes[Task] = {
  18. val dsl = Http4sDsl[Task]
  19. import dsl._
  20. object Value extends QueryParamDecoderMatcher[String]("value")
  21. HttpRoutes.of[Task] {
  22. case GET -> Root / "api" / "books" :?
  23. BookSearchMode.Matcher(mode) +& Value(value) =>
  24. import org.http4s.circe.streamJsonArrayEncoder
  25. import io.circe.syntax._
  26. IO.deferAction(implicit s =>
  27. for {
  28. books <- IO.pure(
  29. libraryService
  30. .searchBook(mode, value)
  31. .toReactivePublisher
  32. .toStream[Task]
  33. )
  34. res <- Ok(books.map(_.asJson))
  35. } yield res
  36. )
  37. case GET -> Root / "api" / "books" =>
  38. import org.http4s.circe.streamJsonArrayEncoder
  39. import io.circe.syntax._
  40. Task.deferAction(implicit s =>
  41. for {
  42. books <- IO.pure(
  43. libraryService.getBooks.toReactivePublisher
  44. .toStream[Task]
  45. )
  46. res <- Ok(books.map(_.asJson))
  47. } yield res
  48. )
  49. case GET -> Root / "api" / "books" / IntVar(id) =>
  50. import org.http4s.circe.CirceEntityCodec._
  51. for {
  52. bookJson <- libraryService.getBookById(id)
  53. res <- Ok(bookJson)
  54. } yield res
  55. case req @ PUT -> Root / "api" / "books" =>
  56. import org.http4s.circe.CirceEntityCodec._
  57. for {
  58. newBook <- req.as[NewBook]
  59. res <- libraryService
  60. .insertBook(newBook)
  61. .tapError(err => logger.errorU(err.toString))
  62. .flatMap(book => Created(book).hideErrors)
  63. .onErrorHandleWith(_.toResponse)
  64. } yield res
  65. case req @ PATCH -> Root / "api" / "books" / IntVar(id) =>
  66. import org.http4s.circe.CirceEntityCodec._
  67. for {
  68. updateData <- req.as[BookUpdate]
  69. res <- libraryService
  70. .updateBook(id, updateData)
  71. .flatMap(_ => NoContent().hideErrors)
  72. .tapError(err => logger.errorU(err.toString))
  73. .onErrorHandleWith(_.toResponse)
  74. } yield res
  75. case req @ DELETE -> Root / "api" / "books" / IntVar(id) =>
  76. for {
  77. _ <- libraryService.deleteBook(id)
  78. res <- Ok()
  79. } yield res
  80. //TODO: use convenience method for decoding json stream
  81. case req @ POST -> Root / "api" / "books" =>
  82. import org.http4s.circe.CirceEntityCodec.circeEntityDecoder
  83. for {
  84. newBooks <- req.as[List[Book]]
  85. // obs = Observable.fromIterable(newBooks)
  86. // book <- libraryService.insertBook(newBook)
  87. res <- Ok("blah")
  88. } yield res
  89. }
  90. }
  91. }
  92. final case class User(id: String, email: String)
  93. object User {
  94. val tupled = (this.apply _).tupled
  95. // implicit val decoder: Decoder[User] = deriveDecoder
  96. // implicit def entityDecoder[F[_]: Sync]: EntityDecoder[F, User] =
  97. // jsonOf
  98. // implicit val encoder: Encoder[User] = deriveEncoder
  99. // implicit def entityEncoder[F[_]: Applicative]: EntityEncoder[F, User] =
  100. // jsonEncoderOf
  101. implicit val codec: Codec[User] = deriveCodec
  102. }