Server Side Swift with Vapor - Part 18: Getting | Ray Wenderlich

Learn how to integrate Leaf into your application and start injecting data into Leaf templates.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/4493-server-side-swift-with-vapor/lessons/18

In the beginning when you say that normally you should split it into an api application and web application is this normal practice? I ask because I’ve used previous frameworks (i.e. Laravel) and it has their templating engine built in as well.

So would there be 2 separate vapor projects where one only takes care of the api (what we just learned from the previous sections) and the other where it’s only the frontend that communicates with the api portion?

Unless I’m missing something, why not put everything together as the leaf templating would be separated from the api files?

@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]

@simonqq yeah exactly. In a ‘modern’ web application you would generally have your front-end (which could be running Leaf) on www.mysite.com. That then makes calls to api.mysite.com either through Javascript or in the Vapor application running the Leaf site.

The reason why you tend to do this is because you don’t want a bit monolithic application that can’t scale very well. Let’s say you have an iOS application, if that gets really popular then you need to grow the API. You don’t want to waste resources building and then running extra front end sites as well. It also means that it is easier to add new features and fix bugs in smaller applications than one large application. It reduces source-control conflicts, typically it would be different dev teams running the API and front-end and co-ordinating releases etc can be difficult. That’s why there has been a big push to microservices over the last few years. Of course you can have common code, so business logic and models etc can all be in a shared module so you don’t duplicate yourself etc.

It is all a matter of scale. For a simple application like the TIL app, there is little point splitting it out. It is just easier to put everything together. If you are building Facebook you don’t want everything in the same application! You just need to find the balance.

Extra argument ‘template’ in call in LeafParcer.swift/:160? How can I add leaf to the project and avoid this mistake?

@aktrader have all of the other videos worked?

yes, right until leaf all worked good
It doesn’t generate project using “3.0.0-beta.1”, project is generated with “3.0.0-rc.1” but I got 21 issues in LeafParcer.swift with Extra argument ‘template’ in call

@aktrader that’s bizarre! First in terminal in the project directory can you try running rm -rf .build TILApp.xcodeproj && swift package update && vapor xcode -y and see if that fixes it?

Yes it worked, thanks

2 Likes

Hi @0xtim, I’ve a problem on “vapor xcode” command.
This is the error:

Error: Could not generate Xcode project: error: terminated(128): git -C /Users/michelemola/Downloads/2-getting-started-with-leaf/part2/TILApp/.build/repositories/console.git–2431895819212044213 rev-parse --verify ‘beta^{commit}’
error: product dependency ‘Vapor’ not found
error: product dependency ‘FluentMySQL’ not found
error: product dependency ‘Leaf’ not found

And this is my Package.swift:

import PackageDescription

let package = Package(
name: “TILApp”,
dependencies: [
// :droplet: A server-side Swift web framework.
.package(url: “GitHub - vapor/vapor: 💧 A server-side Swift HTTP web framework.”, .exact(“3.0.0-beta.2”)),
.package(url: “GitHub - vapor/leaf: 🍃 An expressive, performant, and extensible templating language built for Swift.”, .exact(“3.0.0-beta.2”)),
.package(url: “GitHub - vapor/fluent: Vapor ORM (queries, models, and relations) for NoSQL and SQL databases”, .exact(“3.0.0-beta.2”)),
.package(url: “GitHub - vapor/fluent-mysql-driver: 🖋🐬 Swift ORM (queries, models, relations, etc) built on MySQL.”, .exact(“3.0.0-beta.2”)),
],
targets: [
.target(name: “App”, dependencies: [“FluentMySQL”, “Vapor”, “Leaf”]),
.target(name: “Run”, dependencies: [“App”]),
.testTarget(name: “AppTests”, dependencies: [“App”]),
]
)

@michele your Package.swift may need updating. Try changing all the dependencies from .exact("3.0.0-beta.2") to from: "3.0.0-rc" like the current template. Then do a clean to remove any issues:

rm -rf Package.resolved .build
vapor xcode -y

Hopefully that should fix any issues!

1 Like

Thanks you for your attention, it works.

Best regards,
Michele Mola.

1 Like

When I try to run after I’ve configured leaf with the new directory I go tthis.

    services.register { container -> LeafConfig in
        let dir = try container.make(DirectoryConfig.self)
        return try LeafConfig(
            tags: container.make(),
            viewsDir: dir.workDir + "Resources/Views",
            shouldCache: container.environment != .development
        )
    }

“Use of unresolved identifier ‘DirectoryConfig’”

I sort of solved it by having LeafProvider.swift import Core, but of course that broke other stuff.

All seems fixed when you add import Core to that dependancy. I think it’s missing for now until you fix it and send it out.

@yungdai my PR has been merged and tagged, so if you run vapor update it should pull down the latest code and fix the issue

Awesome! Really looking forward to your book! It’s the final key to a custom App i’m making.

1 Like

Instead of the leaf() extension you wrote, why not just take it all the way?

func renderLeaf<T>(_ path: String, _ context: T) throws -> NIO.EventLoopFuture<TemplateKit.View> where T : Encodable {
    return try self.make(LeafRenderer.self).render(path, context)
}

Then you can call it like return try req.renderLeaf("clients", context)

1 Like

Yep, you can do that, though probably simplify it a bit:

func renderLeaf(_ path: String, _ context: T? = nil) throws -> Future<View> where T : Encodable {
    return try self.make(LeafRenderer.self).render(path, context)
}