├── .gitignore ├── project ├── build.properties └── plugins.sbt ├── .vscode └── settings.json ├── README.md └── src └── main └── scala └── example └── EmberExample.scala /.gitignore: -------------------------------------------------------------------------------- 1 | /.bsp/ 2 | target/ 3 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.7.1 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.7") -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/target": true 4 | } 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scala Native Ember Example 2 | 3 | This is a minimal example showing the configuration to get an ember native application running. 4 | 5 | Setup Locally, s2n is used for SSL. 6 | 7 | ``` 8 | brew install s2n 9 | ``` -------------------------------------------------------------------------------- /src/main/scala/example/EmberExample.scala: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import cats.syntax.all._ 4 | import cats.effect._ 5 | import cats.effect.std.Console 6 | import org.http4s.ember.client.EmberClientBuilder 7 | import org.http4s.ember.server.EmberServerBuilder 8 | import org.http4s._ 9 | import org.http4s.client.Client 10 | import org.http4s.syntax.all._ 11 | import org.http4s.circe._ 12 | import org.http4s.dsl.request._ 13 | import io.circe._ 14 | import epollcat.EpollApp 15 | import fs2.io.net.Network 16 | import fs2.io.net.tls.S2nConfig 17 | import fs2.io.net.tls.TLSContext 18 | 19 | object EmberExample extends EpollApp { 20 | 21 | final case class Joke(joke: String) 22 | object Joke { 23 | implicit val jokeDecoder: Decoder[Joke] = Decoder.derived[Joke] 24 | implicit def jokeEntityDecoder[F[_]: Concurrent]: EntityDecoder[F, Joke] = 25 | jsonOf 26 | } 27 | 28 | def run(args: List[String]): IO[ExitCode] = customTLS 29 | .flatMap(createClient) 30 | .use{ client => 31 | createServer(client).useForever 32 | }.as(ExitCode.Success) 33 | 34 | 35 | def createServer(client: Client[IO]): Resource[IO, Unit] = 36 | EmberServerBuilder.default[IO] 37 | .withHttp2 38 | .withHttpApp(app(client).orNotFound) 39 | .build 40 | .void 41 | 42 | def app(client: Client[IO]) = HttpRoutes.of[IO]{ 43 | case GET -> Root => 44 | Response[IO](Status.Ok).withEntity("Hey There!").pure[IO] 45 | case GET -> Root / "hello" / person => 46 | Response[IO](Status.Ok).withEntity(s"Hello, $person").pure[IO] 47 | case GET -> Root / "joke" => getJoke(client).map(Response(Status.Ok).withEntity(_)) 48 | } 49 | 50 | def getJoke(client: Client[IO]): IO[String] = 51 | client.expect[Joke](Request(Method.GET, uri"https://icanhazdadjoke.com/")) 52 | .map(_.joke) 53 | 54 | def createClient(tlsContext: TLSContext[IO]): Resource[IO, Client[IO]] = { 55 | EmberClientBuilder 56 | .default[IO] 57 | .withTLSContext(tlsContext) 58 | .withHttp2 59 | .build 60 | } 61 | 62 | // TLS 1.3 is not supported without a different default 63 | def customTLS = 64 | S2nConfig.builder 65 | .withCipherPreferences("default_tls13") 66 | .build[IO] 67 | .map(Network[IO].tlsContext.fromS2nConfig(_)) 68 | 69 | } 70 | 71 | object EmberServerExample --------------------------------------------------------------------------------