Skip to content

Instantly share code, notes, and snippets.

@calvinlfer
Created May 8, 2023 13:06
Show Gist options
  • Save calvinlfer/896ed9aadb313526c1ae8301dd67480c to your computer and use it in GitHub Desktop.
Save calvinlfer/896ed9aadb313526c1ae8301dd67480c to your computer and use it in GitHub Desktop.
ZIO HTTP (Graal Native Image & Scala CLI)
#!/bin/sh
scala-cli --power package --native-image -f *.scala -o ziohttp.bin -- --no-fallback --enable-url-protocols=http,https -Djdk.http.auth.tunneling.disabledSchemes= --install-exit-handlers --enable-http --initialize-at-run-time=io.netty.channel.DefaultFileRegion --initialize-at-run-time=io.netty.channel.epoll.Native --initialize-at-run-time=io.netty.channel.epoll.Epoll --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray --initialize-at-run-time=io.netty.channel.kqueue.KQueue --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray --initialize-at-run-time=io.netty.channel.kqueue.Native --initialize-at-run-time=io.netty.channel.unix.Limits --initialize-at-run-time=io.netty.channel.unix.Errors --initialize-at-run-time=io.netty.channel.unix.IovArray --initialize-at-run-time=io.netty.handler.codec.compression.ZstdOptions --initialize-at-run-time=io.netty.incubator.channel.uring.IOUringEventLoopGroup --initialize-at-run-time=io.netty.incubator.channel.uring.Native --initialize-at-run-time=io.netty.handler.ssl.BouncyCastleAlpnSslUtils
//> using scala "3.2.2"
//> using lib "dev.zio::zio:2.0.13"
//> using lib "dev.zio::zio-test:2.0.13"
//> using lib "dev.zio::zio-test-sbt:2.0.13"
//> using lib "dev.zio::zio-http:3.0.0-RC1"
//> using file "ziohttp.scala"
//> using mainClass "ZioHttpApp"
scala-cli run .
import zio.*
import zio.http.*
import zio.http.internal.middlewares.Cors.*
import zio.http.Header.AccessControlAllowOrigin
import zio.http.Path.Segment
object ZioHttpApp extends ZIOAppDefault:
val PORT = 8080
// Create CORS configuration
val corsConfig = CorsConfig(
allowedOrigin = _ => Some(AccessControlAllowOrigin.All),
allowedMethods = Header.AccessControlAllowMethods.All
)
// Add route managers and middleware
val httpProg = HomeApp() ++ GreetingApp()
@@ HttpAppMiddleware.cors(corsConfig)
@@ HttpAppMiddleware.debug
// Server config
val config = Server.Config.default.port(PORT)
val server =
Server.serve(httpProg).provide(ZLayer.succeed(config), Server.live)
val console =
Console.printLine(s"Server starting on http://localhost:${PORT}")
def run = console *> server
object HomeApp:
def apply(): Http[Any, Nothing, Request, Response] =
Http.collect[Request] {
// GET /, redirect to /greet
case Method.GET -> !! =>
Response.redirect(URL(Path.decode("/greet")))
}
object GreetingApp:
def apply(): Http[Any, Nothing, Request, Response] =
Http.collect[Request] {
// GET /greet?name=:name
case req @ (Method.GET -> !! / "greet") if req.url.queryParams.nonEmpty =>
Response.text(
s"Hello ${req.url.queryParams.getOrElse("name", List("User")).mkString(" and ")}!"
)
// GET /greet/:name
case Method.GET -> !! / "greet" / name =>
Response.text(s"Hello $name!")
// GET /greet
case Method.GET -> !! / "greet" =>
Response.text("Hello World!")
}
import zio.http.*
import zio.test.*
import zio.http.Header.Location
object MainSpec extends ZIOSpecDefault:
val homeApp = HomeApp()
val greetApp = GreetingApp()
def spec =
suite("App Tests")(
suite("Main backend application")(
test("should show start message") {
for
_ <- ZioHttpApp.console
output <- TestConsole.output
yield assertTrue(output.head contains "starting")
},
test("root route should redirect to /greet") {
for
response <- homeApp.runZIO(Request.get(URL(!!)))
body <- response.body.asString
yield assertTrue(
response.status == Status.TemporaryRedirect,
response.headers.size == 1,
response.headers.head == Location(URL(!! / "greet")),
body.isEmpty
)
}
),
suite("Greet backend application")(
test("should greet world") {
for
response <- greetApp.runZIO(Request.get(URL(!! / "greet")))
body <- response.body.asString
yield assertTrue(
response.status == Status.Ok,
body == "Hello World!"
)
},
test("should greet User if using path") {
for
response <- greetApp.runZIO(Request.get(URL(!! / "greet" / "User")))
body <- response.body.asString
yield assertTrue(
response.status == Status.Ok,
body == "Hello User!"
)
},
test("should greet User if using param") {
for
response <- greetApp.runZIO(
Request.get(URL(!! / "greet").withQueryParams("?name=User"))
)
body <- response.body.asString
yield assertTrue(
response.status == Status.Ok,
body == "Hello User!"
)
}
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment