Creating Web Pages with Vapor 2 and Swift
This is Part 2 of an ongoing series on Getting Started with Vapor
For this tutorial, we’re going to take what we learned in Part 1 and create some web pages using Vapor’s templating system Leaf. First, let’s talk about what is Leaf. Leaf is a template engine designed to allow us to dynamically display information. Imagine you wanted to create a HTML page that displayed information specific to your current user, you wouldn’t want to have to create new pages for each individual user. With templates, we are able to reuse our code for multiple scenarios. There are several other templating systems we can use such as Mustache and Stencil but as Leaf is built with Swift we will be using it for this tutorial.
First, let’s begin by generating a new vapor project.
Step 1 — Generate a new Vapor project
Open your terminal and enter vapor new hellopages
.
Step 2 — Generate a .xcodeproj
project file
In terminal enter cd hellopages && vapor xcode
. This will take us into the hellopage
folder and run the vapor command to generate the project file. We always want to generate Xcode project files since this gives us access to Xcode’s error checking and code completion which makes coding with Swift significantly easier.
Step 3 — Create a new route for our new web page
First, open the main.swift
file and create a route below the first route. Enter the following code right below the first route.
// 1
drop.get("hello") { req in
//2
return "Hello World"}
This creates a GET request to the route hello
. If we were to run this and navigate to localhost:8080/hello
using a browser we would see “Hello World”.
To create a web page in vapor, we need to change the response to our route. Change the return of the closure to the following
return try drop.view.make(“hello”)
This line tells Vapor to look for a leaf template named hello.leaf
and present it to the user. In case you’re wondering where is the hello.leaf
file we haven’t created it yet.
Your main.swift
file should look like this by now.
Step 4 — Create the hello page.
To create the hello page we will be creating a hello.leaf
file. The .leaf extension is excluded from line 12 above since Leaf is the default templating engine used with Vapor. Template files must be placed in the Resources/Views
folder.
Now let’s create the file. Right Click on Views and Click New File. Call this file hello.leaf
. In this file enter the following code:
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello</h1>
</body>
</html>
You will immediately notice that copying & pasting this code or even writing it out in Xcode doesn’t come with the usual syntax highlighting or indentation we are accustomed to. You can actually set Xcode’s highlighting to HTML for that file. Even though Xcode is built for Swift and Objective C it can be used as an IDE for other languages. You can find this option under Editor
-> Syntax Highlighting
-> HTML
By using the tab button I can adjust the lines slightly to produce the following.
Now go ahead and hit Cmd + R and open your browser to localhost:8080
.
Step 5 — Add some dynamic content
Now let’s take this a little further and send some information from our droplet to our leaf template. Head back to main.swift
and change your helloworld
route to the following.
drop.get("helloworld") { req in
return try drop.view.make("hello", ["greeting": "World"])
}
You will notice that the return here has been changed. We still use the same hello.leaf
file but now we’re passing it what looks like a dictionary
Head back over to your hello.leaf
file and change your file to resemble the following:
<h1>Hello #(greeting)</h1>
By using the #(greeting)
syntax we are able to pass the variable from our return try drop.view.make("hello", ["greeting": "World"])
to our leaf template.
Let’s try adding an array to our route and displaying its contents on the web page with <li></li>
tags
Change the contents of your helloworld
route to the following:
drop.get("helloworld") { req in
let greetings = ["Mundo", "Monde", "Welt"]
return try drop.view.make("hello", ["greeting": "World", "worlds": greetings.makeNode()])}
Here we have added an array called greetings that has the word “World” in Spanish, French and German. In our return, we have added a new key and value pair to our dictionary. You will notice that we call the function makeNode()
on the greetings
array. This function allows us to use our data types on the web pages. Arrays and Dictionaries already have this function built in thanks to Vapor’s extensions. Thankfully in case you ever forget to call makeNode()
the compiler will graciously remind you.
In your hello.leaf
file change your code to the following :
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello #(greeting)</h1>
#loop(worlds, "world") { <li>Hello #(world)</li> }
</body></html>
Here we have added the leaf tag #loop()
which as its name suggests helps us loop through a collection. In #loop()
we are calling on the worlds
key we defined in our route and also passing in a name for each item in our collection i.e world
. This should be very familiar to you in that it resembles the way Swift developers create for in loops. Now that we have a name to represent each item in the array we can use the #()
tag to display each item on the webpage.
There are several other tags included with leaf such as the #if()
and the #raw()
. You can find the full listing in the Vapor Documentation on Leaf
Step 6 — Create a page template
To make our code more reusable, we wouldn’t want to have to include the following every time you create a new .leaf
file.
If you look at the base.leaf
you will notice #import("head")
and #import("body")
. These two lines allow us to dynamically include code from other .leaf
files. We can now update our hello.leaf
file to take advantage of the templating available to them. Change the hello.leaf
file to the following:
#extend("base")
#export("body") {
<head></head>
<body>
<h1>Hello #(greeting)</h1>
#loop(worlds, "world") { <li>Hello #(world)</li> }
</body>
}
At the top, we use the extend()
tag to indicate which .leaf
file we want to include as our template. The string included between the parentheses have to match the exact name of the .leaf
file. The #export()
tag is used to include the content you want to display within the template. The string included in the #export()
tag must match the string included in the #import()
in the .leaf
file you want to include the content in. This technique can help you reuse code and also provide consistent layouts across your web page.
Voila! We’ve created a webpage with Leaf templates. Now it’s your turn to take what you learned from Part 1 and create some more. Good Luck!