2016年2月23日 星期二

用 Swift 開發 Server Side App 並利用 Swift Package Manager - Vapor Framework

首先和各位看官說聲 2016 新年快樂。希望大家在新的一年立訂新的目標。這篇文章要如何用 Vapor 這個 Framework 來開發 Server Side App。Vapor 使用 Swift 來架構而成,個人覺得使用起來比起 Swifton 或是 Kitura 還有 Perfect 來的簡潔。有興趣的可以去多多比較。
而 Vapor 剛好利用 Swift Package Manager 的方式來管理套件,有別於比較常見的 CocoaPods 和 Carthage 來管理,Vapor 使用 Apple 提出的 Swift Package Manager 方式來管理。
要提醒讀者,Vapor 更新還蠻頻繁的所以 Google 到的寫法可能是舊的,請看好 Vapor 的版本,這篇用的是 0.2.3 。筆者會持續更新。

安裝 Swift 3.0 Dev


準備工具:Swift 3.0 Dev 從這邊下載,目前 Swift 2.2 Release 還沒支援 Swift Package Manager 所以要下載 Latest Development Snapshot 。
作業環境: OS X El Capitan 10.11.2
下載完會看到一個 swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-osx.pkg
點兩下安裝。如果沒有看到如下安裝畫面
 
這是安全的考量,Mac 認為這個程式不是認證的開發者???
要手動打開,系統偏好設定->安全性與隱私
安裝好之後會在
 /Library/Developer/Toolchains/
看到這幾個資料夾
swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a.xctoolchain/
swift-latest.xctoolchain/
之後就用 swift-latest.xctoolchain/ 就可以了
試一下 Swift 版本
打開 Terminal 輸入以下指令
 /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swift --version
看結果是不是以下
Apple Swift version 3.0-dev (LLVM a7663bb722, Clang 4ca3c7fa28, Swift 1c2f40e246)
Target: x86_64-apple-macosx10.9
如果是 3.0-dev 就沒有問題了。
為了省輸入時間可以在.profile 檔加上
export PATH=/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin:$PATH
開啟 Terminal 就執行  .profile 這樣就直接用 swift 就好了。

建立 Vapor 專案

建立一個資料夾名為 swiftServer,其架構如下
swiftServer/
├── Package.swift
├── Resources
│   └── index.html
└── Sources
    └── main.swift

Package 內容如下
 
import PackageDescription

let package = Package(
name: "SwiftServer",
dependencies: [
.Package(url: "https://github.com/tannernelson/vapor.git", majorVersion: 0)
 ]
)
稍微解釋一下,Package.swift 的語法也是 Swift 一開始要 import PackageDescription 接著就可以用 Package 這個 class 有興趣的讀者可以在這看到 Package 的全貌。majorVersion 爲 0 因為現在 Vapor 的版本是 0.2.1 majorVersion 爲 0 依照 source code 會找 0..<1 的版本

main.swift 內容如下
 
import Vapor

let app = Application()
app.get("welcome") { request in
 return "Hello Vapor"
}
app.start(port:8080) 
Vapor 裡面有 Application 這個 class 也就 Server 一直執行的 Daemon 。然後綁定在 port 8080,
接著我們利用 app.get 來定義 HTTP GET Method 的 Path。目在這個例子新增 /welcome 這個 Path。
是時候在本機來執行這個 Vapor server 。
在 Package.swift 同一個目錄下,在 Terminal 輸入以下指令。
swift build

成功之後會看到

Cloning https://github.com/tannernelson/vapor.git
Using version 0.2.3 of package vapor
Compiling Swift Module 'Vapor' (32 sources)
/Users/michael/Documents/project/swiftServer/Packages/vapor-0.2.3/Sources/Application+Route.swift:108:13: warning: variable 'handler' was never mutated; consider changing to 'let' constant
        var handler = { request in
        ~~~ ^
        let
Linking Library:  .build/debug/Vapor.a
Compiling Swift Module 'SwiftServer' (1 sources)
Linking Executable:  .build/debug/SwiftServer

看到目前的 Vapor 版本為 0.2.3
然後這理有個 Warning 是 Swift compiler 常見的 Warning ,建議把 var 改成 let 。雖然我們有 source code 但是還是不建議自己改,就給 Vapor 維護者在一個版本改。最後一行是 Linking Executable:  .build/debug/SwiftServer 就是代表 compiler 完的執行檔。
只要在 Terminal 直接執行
.build/debug/SwiftServer
會看到
Server has started on port 8080

然後打開本機的 Browser 在 URL 的地方輸入
http://localhost:8080/welcome

就會看到如下



幾件事提醒

1. 如果有修改 code 要重新利用 swift build 來 compile 之前,請先用 rm .build/debug/SwiftServer 把舊的執行檔刪除。
2. 程式碼的 app.start(port:8080) 請務必是最後一行。
3. 也可以輸出 JSON 比如直接回傳 [ "name":"Michael"],留給讀者自行嘗試。

HTML 結合

輸出的結果有時候需要是 html ,Vapor 也可以輸出已經編寫好的 html 檔案,但必須放在 Resources 這個資料裡面,在看一次專案結構圖。
swiftServer/
├── Package.swift
├── Resources
│   └── index.html
└── Sources
    └── main.swift

在這 index.html 的內容為

 <html>
    <body>
        <h1>Vapor Server</h1>
This is tutorial for building Vapor Server.
    </body>
</html>
輸入好之後在 main.swift 新增一個 Path
修改完如下
 
import Vapor

let app = Application()
app.get("welcome") { request in
 return "Hello Vapor"
}
app.get("view") { request in
    var view:View? = nil
    do {
        try view = View(path: "index.html")
    }catch {
        print("can not find html : error")
    }
    if let okView = view {
        return okView
    }
    return "Error"
}
app.start(port:8080) 
我們新增了 /view 這個 path。 要注意的是 View 這個 class 的 init?(path:) 會丟出 error,所以要用 do-try-catch 來承接。
最後把 unwrapped 的 okView 回傳就好了。
先把 Server 停掉,ctrl+C
記得
1. rm  .build/debug/SwiftServer
2. swift build

再重新執行
.build/debug/SwiftServer

打開 Browser 輸入,http://localhost:8080/view
會看到


如果這篇很多人回應我們再來分享一篇,如何結合 Database。很多人是多少呢?超過 300 人吧?試試人氣。


4 則留言:

  1. 頭推
    目前看起來是跟sql lite?

    回覆刪除
  2. 不是喔,是server side的 Database 不是 local的。

    回覆刪除
  3. 在我 build 的时候提示 error: no such module 'PackageDescription' 请问这是什么问题

    回覆刪除
  4. Vapor中文版文档:https://github.com/CaryZheng/Vapor-Chinese

    回覆刪除