Creating Web Pages with Vapor 2 and Swift

Johann Kerr
6 min readFeb 9, 2017

--

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!

--

--

Johann Kerr

Software Engineer @FlatironSchool, formerly Lead iOS & Web Instructor at //