mitrakov

Simple Http4s with Tapir

Apr 15th, 2020
470
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 1.87 KB | None | 0 0
  1. import cats.Monad
  2. import cats.effect.{IOApp, IO, ExitCode, Sync, ContextShift, ConcurrentEffect, Timer}
  3. import fs2.Stream
  4. import io.circe.generic.auto._
  5. import org.http4s.HttpApp
  6. import org.http4s.server.Router
  7. import org.http4s.server.blaze.BlazeServerBuilder
  8. import org.http4s.server.middleware.Logger
  9. import sttp.tapir.json.circe._
  10.  
  11. object Main extends IOApp {
  12.   type Id = Long
  13.   type Name = String
  14.   type Status = Int
  15.   type Token = String
  16.  
  17.   case class User(id: Id, name: Name)
  18.   case class UserInfo(user: User, info: String)
  19.  
  20.   override def run(args: List[String]): IO[ExitCode] = {
  21.     import cats.implicits._
  22.  
  23.     val app: HttpApp[IO] = createApp[IO]
  24.     val loggedApp: HttpApp[IO] = Logger.httpApp(logHeaders = true, logBody = true)(app)
  25.     val server: Stream[IO, ExitCode] = createServer(app = loggedApp)
  26.     server.compile.drain.as(ExitCode.Success)
  27.   }
  28.  
  29.   def createApp[F[_]: Sync: ContextShift]: HttpApp[F] = {
  30.     import sttp.tapir._
  31.     import sttp.tapir.server.http4s._
  32.     import org.http4s.implicits._
  33.     import cats.syntax.applicative.catsSyntaxApplicativeId
  34.     import cats.syntax.either.catsSyntaxEitherId
  35.  
  36.     // GET localhost:8080/users/555/tommy?status=2
  37.     val myEndpoint: Endpoint[(User, Status, Token), Unit, UserInfo, Nothing] = endpoint
  38.       .get
  39.       .in(("users" / path[Id]("id") / path[Name]("name")).mapTo(User))
  40.       .in(query[Status]("status"))
  41.       .in(header[Token]("X-Auth"))
  42.       //.errorOutput(stringBody)
  43.       .out(jsonBody[UserInfo])
  44.  
  45.     def logic(u: User, s: Status, t: Token): F[Either[Unit, UserInfo]] = implicitly[Monad[F]].pure {
  46.       Right[Unit, UserInfo](UserInfo(u, s"Status is $s, token is $t"))
  47.     }
  48.     val route1 = myEndpoint.toRoutes((logic _).tupled)
  49.     // val route2 = otherEndpoint.toRoutes(_ => "hello".asRight[Throwable].pure)
  50.     val routes = route1 // <+> route2
  51.  
  52.     Router("/" -> routes).orNotFound
  53.   }
  54.  
  55.   def createServer[F[_]: ConcurrentEffect: Timer](host: String = "0.0.0.0", port: Int = 8080, app: HttpApp[F]): Stream[F, ExitCode] = {
  56.     BlazeServerBuilder[F].bindHttp(port, host).withHttpApp(app).serve
  57.   }
  58. }
Add Comment
Please, Sign In to add comment