feat(01): Simple initial landing

This commit is contained in:
Jakub Zych
2026-02-05 13:01:34 +01:00
parent d502bb19a5
commit 7b5fe94e53
8 changed files with 295 additions and 11 deletions

View File

@@ -0,0 +1,62 @@
package api
import zio.*
import zio.http.*
import scala.io.Source
/** Landing page and static asset routes
*/
object LandingRoutes {
private def loadResource(path: String): Option[String] =
Option(getClass.getClassLoader.getResourceAsStream(path)).map { stream =>
val content = Source.fromInputStream(stream, "UTF-8").mkString
stream.close()
content
}
private def serveLanding: ZIO[Any, Nothing, Response] =
ZIO.succeed {
loadResource("public/landing.html") match {
case Some(html) =>
Response(
status = Status.Ok,
headers = Headers(Header.ContentType(MediaType.text.html)),
body = Body.fromString(html)
)
case None =>
Response.text("Landing page not found").status(Status.InternalServerError)
}
}
private def serveImage(filename: String): ZIO[Any, Nothing, Response] =
ZIO.attemptBlocking {
val path = s"public/assets/images/$filename"
val stream = getClass.getClassLoader.getResourceAsStream(path)
if (stream == null) {
Response.notFound
} else {
val bytes = stream.readAllBytes()
stream.close()
val mediaType = if (filename.endsWith(".png")) MediaType.image.png
else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) MediaType.image.jpeg
else if (filename.endsWith(".svg")) MediaType.image.`svg+xml`
else if (filename.endsWith(".gif")) MediaType.image.gif
else MediaType.application.`octet-stream`
Response(
status = Status.Ok,
headers = Headers(Header.ContentType(mediaType)),
body = Body.fromChunk(Chunk.fromArray(bytes))
)
}
}.catchAll(_ => ZIO.succeed(Response.notFound))
val routes: Routes[Any, Response] =
Routes(
Method.GET / Root -> handler(serveLanding),
Method.GET / "assets" / "images" / string("filename") -> handler { (filename: String, _: Request) =>
serveImage(filename)
}
)
}

View File

@@ -10,6 +10,6 @@ import javax.sql.DataSource
object Routes {
val routes: Routes[DataSource, Response] =
HealthRoutes.routes
LandingRoutes.routes ++ HealthRoutes.routes
}