The Scala Toolkit

How to serve a static file?

Language

You can declare a dependency on Cask with the following using directive:

//> using dep "com.lihaoyi::cask::0.9.2"

In your build.sbt, you can add a dependency on Cask:

lazy val example = project.in(file("example"))
  .settings(
    scalaVersion := "3.4.2",
    libraryDependencies += "com.lihaoyi" %% "cask" % "0.9.2",
    fork := true
  )

In your build.sc, you can add a dependency on Cask:

object example extends RootModule with ScalaModule {
  def scalaVersion = "3.3.3"
  def ivyDeps = Agg(
    ivy"com.lihaoyi::cask::0.9.2"
  )
}

Serving a static file

An endpoint is a specific URL where a particular webpage can be accessed. In Cask, an endpoint is a function returning the webpage data, together with an annotation describing its URL.

To create an endpoint serving static files, we need two things: an HTML file with the page content and a function that points to that file.

Create a minimal HTML file named hello.html with the following contents.

<!doctype html>
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
        <h1>Hello world</h1>
    </body>
</html>

Place it in the resources directory.

example
├── Example.scala
└── resources
     └── hello.html
example
└──src
    └── main
        ├── resources
        │   └── hello.html
        └── scala
            └── Example.scala
example
├── src
│    └── Example.scala
└── resources
     └── hello.html

The @cask.staticFiles annotation specifies at which path the webpage will be available. The endpoint function returns the location of the file.

object Example extends cask.MainRoutes {
  @cask.staticFiles("/static")
  def staticEndpoint(): String = "src/main/resources" // or "resources" if not using SBT

  initialize()
}
object Example extends cask.MainRoutes:
  @cask.staticFiles("/static")
  def staticEndpoint(): String = "src/main/resources" // or "resources" if not using SBT

  initialize()

In the example above, @cask.staticFiles instructs the server to look for files accessed at the /static path in the src/main/resources directory. Cask will match any subpath coming after /static and append it to the directory path. If you access the /static/hello.html file, it will serve the file available at src/main/resources/hello.html. The directory path can be any path available to the server, relative or not. If the requested file cannot be found in the specified location, the server will return a 404 response with an error message.

The Example object inherits from the cask.MainRoutes class. It provides the main function that starts the server. The initialize() method call initializes the server routes, i.e., the association between URL paths and the code that handles them.

Using the resources directory

The @cask.staticResources annotation works in the same way as the @cask.staticFiles used above, with the difference that the path returned by the endpoint method describes the location of files inside the resources directory. Since the previous example conveniently used the resources directory, it can be simplified with @cask.staticResources.

object Example extends cask.MainRoutes {
  @cask.staticResources("/static")
  def staticEndpoint(): String = "."

  initialize()
}
object Example extends cask.MainRoutes:
  @cask.staticResources("/static")
  def staticEndpoint(): String = "."

  initialize()

In the endpoint method, the location is set to ".", telling the server that the files are available directly in the resources directory. In general, you can use any nested location within the resources directory. For instance, you could opt for placing your HTML files in the static directory inside the resources directory or using different directories to sort out files used by different endpoints.

Running the example

Run the example with the build tool of your choice.

In the terminal, the following command will start the server:

scala run Example.scala

In the terminal, the following command will start the server:

sbt example/run

In the terminal, the following command will start the server:

./mill run

The example page will be available at http://localhost:8080/static/hello.html.

Contributors to this page: