Created
June 15, 2024 07:58
-
-
Save dacr/84f026b451b902be080f31f699e0ac96 to your computer and use it in GitHub Desktop.
Simple server side event (SSE) using http4s library and zio dependency injection / published by https://github.com/dacr/code-examples-manager #c52505e2-38d1-49ee-8bbc-d8ee46c69c1d/f2a9bdcd84561be43525370801f7e2720fb9494c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// summary : Simple server side event (SSE) using http4s library and zio dependency injection | |
// keywords : scala, http4s, cats, http-server, tapir, sse, zio, @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 : c52505e2-38d1-49ee-8bbc-d8ee46c69c1d | |
// created-on : 2024-06-14T13:47:45+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 // MANDATORY for scala3 kind projector, cats need | |
// --------------------- | |
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.PublicEndpoint | |
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.ztapir.* | |
import zio.interop.catz.* | |
import zio.{Console, Task, UIO, ZIO, RIO, URIO, ZIOAppDefault, ZLayer} | |
import zio.durationInt | |
import zio.stream.* | |
trait GreetingsService { | |
def standardGreetings: UIO[List[String]] | |
} | |
case class GreetingsServiceLive() extends GreetingsService { | |
override def standardGreetings: UIO[List[String]] = ZIO.succeed { | |
List("Hi", "Hello", "Good morning", "How are you") | |
} | |
} | |
object GreetingsService { | |
def standardGreetings: URIO[GreetingsService, List[String]] = ZIO.serviceWithZIO[GreetingsService](_.standardGreetings) | |
val live = ZLayer.succeed(GreetingsServiceLive()) | |
} | |
object Hello extends ZIOAppDefault { | |
def hiLogic(givenName: Option[String]): URIO[GreetingsService, Stream[Throwable, ServerSentEvent]] = for { | |
greetings <- GreetingsService.standardGreetings | |
stream = ZStream | |
.from(greetings) | |
.map(greeting => givenName.map(name => s"$greeting $name").getOrElse(greeting)) | |
.forever | |
.map(greeting => ServerSentEvent(data = Some(greeting))) | |
.take(10) | |
} yield stream | |
val hiEndPoint = | |
endpoint | |
.description("Returns many greetings") | |
.get | |
.in("hi") | |
.in(query[Option[String]]("name").description("someone name")) | |
.out(serverSentEventsBody) | |
val hiEndPointWired = hiEndPoint.zServerLogic[GreetingsService](hiLogic) | |
val docEndPointWired = | |
SwaggerInterpreter() | |
.fromServerEndpoints( | |
List(hiEndPointWired), | |
Info(title = "Greeting API", version = "1.0", description = Some("Everything required to be polite")) | |
) | |
val routes: HttpRoutes[RIO[GreetingsService, _]] = | |
ZHttp4sServerInterpreter() | |
.from(hiEndPointWired :: docEndPointWired) | |
.toRoutes | |
def run = { | |
ZIO.executor | |
.flatMap(executor => | |
BlazeServerBuilder[RIO[GreetingsService, _]] | |
.withExecutionContext(executor.asExecutionContext) | |
.bindLocal(8080) | |
.withHttpApp(Router("/" -> routes).orNotFound) | |
.serve | |
.compile | |
.drain | |
) | |
.timeout(60.seconds) | |
.provide(GreetingsService.live) | |
} | |
} | |
Hello.main(Array.empty) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment