Static Files

On static data and HTTP

Usually, if you fetch a file via HTTP, it ships with an ETag. An ETag specifies a file version. So the next time the browser requests that information, it sends the ETag along, and gets a 304 Not Modified back, so you don’t have to send the data over the wire again.

All of these solutions are most likely slower than the equivalent in nginx or a similar static file hoster, but they’re often fast enough.

Serving static files

Http4s provides a few helpers to handle ETags for you, they’re located in StaticFile.

import cats.effect._
import org.http4s._
import org.http4s.dsl.io._
import java.io.File

val service = HttpService[IO] {
  case request @ GET -> Root / "index.html" =>
    StaticFile.fromFile(new File("relative/path/to/index.html"), Some(request))
      .getOrElseF(NotFound()) // In case the file doesn't exist
}
// service: HttpService[IO] = Kleisli(
//   org.http4s.HttpService$$$Lambda$12903/708292025@1d3ac700
// )

Serving from jars

For simple file serving, it’s possible to package resources with the jar and deliver them from there. Append to the List as needed.

def static(file: String, request: Request[IO]) =
  StaticFile.fromResource("/" + file, Some(request)).getOrElseF(NotFound())

val service2 = HttpService[IO] {
  case request @ GET -> Root / path if List(".js", ".css", ".map", ".html", ".webm").exists(path.endsWith) =>
    static(path, request)
}
// service2: HttpService[IO] = Kleisli(
//   org.http4s.HttpService$$$Lambda$12903/708292025@19ba4416
// )

Webjars

A special service exists to load files from WebJars. Add your WebJar to the class path, as you usually would:

libraryDependencies ++= Seq(
  "org.webjars" % "jquery" % "3.1.1-1"
)

Then, mount the WebjarService like any other service:

import org.http4s.server.staticcontent.webjarService
import org.http4s.server.staticcontent.WebjarService.{WebjarAsset, Config}

// only allow js assets
def isJsAsset(asset: WebjarAsset): Boolean =
  asset.asset.endsWith(".js")

val webjars: HttpService[IO] = webjarService(
  Config(
    filter = isJsAsset
  )
)
// webjars: HttpService[IO] = Kleisli(
//   org.http4s.server.staticcontent.WebjarService$$$Lambda$12904/1241558711@3f5ce12b
// )