Create a custom Leaf tag in Vapor

Vapor

I’ve been recently interested in server-side Swift and stumbled upon the Vapor framework.

Vapor is a cool web-application development framework written in Swift. It’s partially inspired by Laravel / Lumen, so if you’re familiar with it, you’ll probably feel at home.

While the above information is true, there’re still some differences. As opposed to Laravel and its Blade templating engine, Vapor uses Leaf.

It’s new and sometimes lacks documentation, so I’ve decided to write this article and explain how to extend it.

What is a custom tag in Leaf?

Custom tags are basically functions which are available in templates. It’s something similar to helpers from Laravel and Rails world.

The simplest example could be a function outputting the current year.

Custom tags in Leaf are supposed to conform to BasicTag protocol (interface) which looks like this:

public protocol BasicTag: Tag {
    func run(arguments: [Argument]) throws -> Node?
}

Let’s create a class implementing this interface (I’ve created it in the Sources/ProjectName/Leaf/Tags directory):

import Leaf
import Foundation

public class Year: BasicTag {
    public func run(arguments: [Argument]) throws -> Node? {

    }
}

Every single tag in Vapor has to have a name property which will be the name of your “helper”, so you can call it within a template.

import Leaf
import Foundation

public class Year: BasicTag {
    // here's the name property
    public let name = "year"

    public func run(arguments: [Argument]) throws -> Node? {

    }
}

Finally, let’s implement the functionality itself:

import Leaf
import Foundation

public class Year: BasicTag {
    // here's the name property
    public let name = "year"

    public func run(arguments: [Argument]) throws -> Node? {
        // get the current date and time
        let currentDateTime = Date()

        // get the current calendar
        let calendar = Calendar.current

        // get the year
        let dateTimeComponents = calendar.dateComponents([.year], from: currentDateTime)

        // convert it to Node?, so it conforms to the protocol
        return Node(dateTimeComponents.year!)
    }
}

Good. Now we have our custom tag but we can’t access it in templates yet. To assess this, we have to register our new tag in a view renderer.

Register the helper in a ViewRenderer

To register the custom tag, open the main.swift file and put the following code after the Droplet initialization:

if let leaf = drop.view as? LeafRenderer {
    leaf.stem.register(Year())
}

Vapor supports many different view renderers. As our custom tag is intended to be used only with Leaf, we have to register it only when our project uses the LeafRenderer.

The above code basically means “If the current droplet’s renderer is compatible with LeafRenderer, register the Year() tag in its stem”.

That’s it!

Now you can use the #year() helper in your Leaf templates.

← Back