Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active June 19, 2024 22:08
Show Gist options
  • Save dacr/4445029739bf2b9de65acb37830330c3 to your computer and use it in GitHub Desktop.
Save dacr/4445029739bf2b9de65acb37830330c3 to your computer and use it in GitHub Desktop.
json based server side event (SSE) using http4s library / published by https://github.com/dacr/code-examples-manager #d28f73c2-dad9-4576-b710-83b87d4a3f09/a73bb81a1acdfe9bd11afd9d0aa511ea175a17d5
// summary : json based server side event (SSE) using http4s library
// keywords : scala, http4s, cats, http-server, tapir, sse, @testable, @exclusive
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : d28f73c2-dad9-4576-b710-83b87d4a3f09
// created-on : 2024-06-13T15:59:48+02:00
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// test-with : curl http://127.0.0.1:8080/hi
// ---------------------
//> using scala "3.4.2"
//> using dep "com.softwaremill.sttp.tapir::tapir-zio:1.10.9"
//> using dep "com.softwaremill.sttp.tapir::tapir-http4s-server-zio:1.10.9"
//> using dep "com.softwaremill.sttp.tapir::tapir-json-zio:1.10.9"
//> using dep "com.softwaremill.sttp.tapir::tapir-swagger-ui-bundle:1.10.9"
//> using dep "com.softwaremill.sttp.tapir::tapir-openapi-docs:1.10.9"
//> using dep "org.http4s::http4s-blaze-server:0.23.16"
//> using dep "org.slf4j:slf4j-simple:2.0.13"
//> using options -Ykind-projector:underscores
// ---------------------
import cats.syntax.all.*
import org.http4s.{ServerSentEvent as _, *}
import org.http4s.blaze.server.BlazeServerBuilder
import org.http4s.server.Router
import org.http4s.implicits.*
import sttp.tapir.generic.auto.*
import sttp.tapir.swagger.bundle.SwaggerInterpreter
import sttp.tapir.server.http4s.ztapir.{ZHttp4sServerInterpreter, serverSentEventsBody}
import sttp.apispec.openapi.Info
import sttp.model.sse.ServerSentEvent
import sttp.tapir.Schema
import sttp.tapir.ztapir.*
import sttp.tapir.json.zio.*
import zio.interop.catz.*
import zio.{Console, Task, UIO, ZIO, ZIOAppDefault}
import zio.durationInt
import zio.stream.*
import zio.json.*
case class Greeting(message: String) derives JsonCodec
object Hello extends ZIOAppDefault {
def hiLogic(givenName: Option[String]): UIO[Stream[Throwable, ServerSentEvent]] = ZIO.succeed {
ZStream
.from(List("Hi", "Hello", "Good morning", "How are you"))
.map(greeting => givenName.map(name => s"$greeting $name").getOrElse(greeting))
.map(Greeting.apply)
.forever
.map(greeting => ServerSentEvent(data = Some(greeting.toJson)))
.take(10)
}
val hiEndPoint =
endpoint
.description("Returns many greetings using ServerSentEvent")
.get
.in("hi")
.in(query[Option[String]]("name").description("someone name"))
.out(
serverSentEventsBody
.schema(
Schema.derived[Greeting].as[Stream[Throwable, ServerSentEvent]]
)
)
val hiEndPointWired = hiEndPoint.zServerLogic[Any](hiLogic)
val docEndPointWired =
SwaggerInterpreter()
.fromServerEndpoints(
List(hiEndPointWired),
Info(title = "Greeting API", version = "1.0", description = Some("Everything required to be polite"))
)
val routes: HttpRoutes[Task] = ZHttp4sServerInterpreter()
.from(hiEndPointWired :: docEndPointWired)
.toRoutes
def run = {
ZIO.executor.flatMap(executor =>
BlazeServerBuilder[Task]
.withExecutionContext(executor.asExecutionContext)
.bindLocal(8080)
.withHttpApp(Router("/" -> routes).orNotFound)
.serve
.compile
.drain
) // .timeout(60.seconds)
}
}
Hello.main(Array.empty)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment