decochのブログ

フリーランスのiOSエンジニア decoch のブログです

VaporとLeafを使ったサンプルアプリケーションの実装

はじめに

Vapor Advent Calendar 2018の2日目の記事です

今回はLeafを使って、サーバーサイドレンダリングを行うサンプルアプリケーションの実装をしていきます。

アプリの作成

まずはVaporのコマンドを使ってアプリの雛形を作成しましょう。

vapor を brew インストールします。詳細

brew install vapor/tap/vapor

インストールが完了すると vaporコマンドで新しくアプリが作成できます。

vapor new sample-app

f:id:decoch:20181128230812p:plain
result

tree sample-app

sample-app
├── Package.resolved
├── Package.swift
├── Public
├── README.md
├── Sources
│   ├── App
│   │   ├── Controllers
│   │   │   └── TodoController.swift
│   │   ├── Models
│   │   │   └── Todo.swift
│   │   ├── app.swift
│   │   ├── boot.swift
│   │   ├── configure.swift
│   │   └── routes.swift
│   └── Run
│       └── main.swift
├── Tests
│   ├── AppTests
│   │   └── AppTests.swift
│   └── LinuxMain.swift
├── cloud.yml
└── web.Dockerfile

8 directories, 14 files

これでアプリの雛形が出来上がりました。

Xcodeで起動

続いてXcodeで起動できるように設定をしてきます。

といっても簡単でコマンドを2回実行するだけです。

cd sample-app
vapor xcode

Xcodeで開くか確認されるので y としましょう

Generating Xcode Project [Done]
Select the `Run` scheme to run.
Open Xcode project?
y/n> y

Xcode上でRun(⌘+R)を実行し、localhost:8080 にアクセスするとアプリが起動できます。

f:id:decoch:20181128231407p:plain
it-work!!

アプリに起動が確認できました

Leafの設定

今回はHTMLテンプレートを使ったサンプルを作るので Leaf というライブラリを使います。

早速設定をしていきましょう!

Package.swift を編集して Leafを追加します。

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "sample-app",
    dependencies: [
        // 💧 A server-side Swift web framework.
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
        .package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"), // 追加

        // 🔵 Swift ORM (queries, models, relations, etc) built on SQLite 3.
        .package(url: "https://github.com/vapor/fluent-sqlite.git", from: "3.0.0")
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentSQLite", "Vapor", "Leaf"]), // Leafを追加
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

Xcodeを一度終了してターミナルからコマンドを実行してライブラリをダウンロードします。

vapor update -y

ダウンロードが完了したら、Leafを使う設定を記述しています。

configure.swift

import FluentSQLite
import Vapor
import Leaf  // import を追加

/// Called before your application initializes.
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    /// Register providers first
    try services.register(FluentSQLiteProvider())

    /// Register routes to the router
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)
    
    /// Leafの設定を追加
    let leafProvider = LeafProvider()
    try services.register(leafProvider)
    config.prefer(LeafRenderer.self, for: ViewRenderer.self)

    /// Register middleware
    var middlewares = MiddlewareConfig() // Create _empty_ middleware config
    /// middlewares.use(FileMiddleware.self) // Serves files from `Public/` directory
    middlewares.use(ErrorMiddleware.self) // Catches errors and converts to HTTP response
    services.register(middlewares)

    // Configure a SQLite database
    let sqlite = try SQLiteDatabase(storage: .memory)

    /// Register the configured SQLite database to the database config.
    var databases = DatabasesConfig()
    databases.add(database: sqlite, as: .sqlite)
    services.register(databases)

    /// Configure migrations
    var migrations = MigrationConfig()
    migrations.add(model: Todo.self, database: .sqlite)
    services.register(migrations)

}

これで設定が完了しました。

サンプル画面を作ってみる

サンプル画面を作成してみましょう。

以下のようにテンプレートファイルを作成します。

※ 拡張子が.leafであることに注意してください

f:id:decoch:20181128233014p:plain
directory

<!DOCTYPE html>
<html>
<head>
  <title>Leaf</title>
</head>
<body>
  <h1>Hello from Leaf.</h1>
</body>
</html>

続いてテンプレートとURLを紐付けるためにRoutingの設定をします。

/// Register your application's routes here.
public func routes(_ router: Router) throws {
    // 省略
    
    // 追加
    router.get("hello") { req -> Future<View> in
        return try req.view().render("hello")
    }
}

これでテンプレートを表示する設定が完了しました。

⌘+R でアプリを再起動しましょう

f:id:decoch:20181128233314p:plain
hello

HTML ファイルの内容が画面に表示されました!!

動的な値を表示する

最後に構造体のデータを画面に表示してみます、

まずは動的にデータを表示するためのテンプレートを作成します。

f:id:decoch:20181128235244p:plain
TODOのテンプレート

続いて以下ように routes.swift に追記をします。

public func routes(_ router: Router) throws {
    // 省略

    // 追加
    router.get("sample/todos") { req -> Future<View> in
        struct todos: Codable {
            let todos = [Todo(id: 1, title: "洗濯をする"), Todo(id: 2, title: "ご飯をつくる")]
        }
        return try req.view().render("todo", todos())
    }
}

⌘+R でアプリを再起動しましょう

f:id:decoch:20181128235346p:plain
TODOの表示結果

構造体のデータが画面に表示されました!!

まとめ

  • VaporでSwiftの構造体を画面に表示するところまで実装をしました。
  • 実践的なアプリを作成する場合は、構造体のところをDBから取得した値に変更すれば実現できます。(時間の関係で今回はそこまでたどり着きませんした)
  • SwiftはiOSでしか使わないような印象がありますがWebフレームワークもあるので実装してみましょう!!