Serving HTML
There are three different ways in which you can serve HTML content from a Ktor application. We explore two of them below. The third approach, using templates, will be covered later.
Serving Static Files
You can serve static content from three different places:
- The filesystem
- A Zip archive
- The application classpath
The first two of these are configured using the staticFiles() and
staticZip() functions, respectively. The third option is configured using
the staticResources() function.
These functions are all called as part of setting up the routing of the application.
Let’s experiment with the third option.
-
Download
ktor-static.zipfrom the Topic 2 folder in Minerva, then unzip this archive in your SoCS Linux filestore or your own PC. -
Examine the contents of the directory that is created. This is an Amper project for a very basic Ktor application. Take a look at
Routing.ktand you can see thatstaticResources()has been used:fun Application.configureRouting() { routing { staticResources("/", "static") } }This declares that Ktor should try to satisfy GET requests by serving content from a directory named
static, located in the application classpath, alongside the code of the application.Because there is no other routing declared here using
get()or other request handling functions, all requests will be treated as if they are for static resources; in other words, this Ktor server will function like a classic web server, serving HTML, CSS, images and other files. -
Run the application with
./amper run(Note: this is for Linux & macOS; adjust this and subsequent commands as necessary if you are using Windows.)
If you try visiting the application home page you should get a
404 Not Founderror, because there are as yet no HTML files.Stop the server with
Ctrl+C. -
Create a file named
index.html, in the directoryresources/static. Any files that we want our server to use should be placed here. They are not served from here at runtime, but this is where they have go so that they are bundled with the application code whenever it is compiled.In
index.html, create a web page. Use the Pico CSS framework to style it nicely, and include an image or two. Remember that you will also need to put the image files in thestaticsubdirectory. -
Rebuild the application with
./amper buildExamine the contents of
build/tasks/_ktor-static_compileJvm. You should see the.classfiles of the application here, along with astaticsubdirectory containingindex.htmland any image files that you added. -
Run the application with
./amper runVisit
http://0.0.0.0:8080again and you should now see a nicely styled web page.
Constructing HTML Dynamically
Another approach is to create a response dynamically using Kotlin code. The
kotlinx.html library provides a neat way of doing this. It defines a
domain-specific language (DSL) for building HTML documents. Ktor
integrates this approach and allows you to use it, in conjunction with the
respondHtml() function, to issue HTML documents as responses to a request.
Let’s examine a demo application.
-
Download
ktor-html.zipfrom the Topic 2 folder in Minerva, then unzip this archive in your SoCS Linux filestore or your own PC. -
Examine the contents of the directory that is created. This is another Amper-based Ktor project, a small web application that simulates die rolls.
If you look at
Routing.ktyou’ll see that it defines a single route for GET requests with URLs that match/roll/dfollowed by the number of die sides.routing { get("/roll/d{sides}") { val sides: Int by call.parameters val number = dieRoll(sides) call.respondHtml(HttpStatusCode.OK) { head { title { +"Dice Roller" } } body { h1 { +"d${sides} Dice Roll" } p { +"Result = $number" } } } } }The first thing done to handle the request is link the parameters of the call (the data encoded into the URL or request body) with variables. In this case, there is just the one variable,
sides. Thebykeyword indicates that this is done using Kotlin’s delegated properties feature.After this, a function is called to roll the die (see
Dice.ktfor its implementation). Then an HTML page giving the result of the die roll is built, using the DSL mentioned earlier. Notice how Kotlin syntax is used to build a nested structure of HTML elements here. -
Run the application with
./amper runVisit
http://0.0.0.0:8080/roll/d20in your browser to see the response created by the application. Refresh the page to roll a d20 again.Use your browser’s ‘View Page Source’ feature to examine the raw HTML.
-
Try changing the number of die sides to one of the other allowed values (4, 6, 8, 10, 12). Then investigate what happens if you specify an invalid number, or provide something that isn’t a number at all. Why do you think the server doesn’t crash when you do this?
-
Experiment with modifying the HTML of the die roll results page or the error page, so that you can get a feel for this DSL-based approach.