在2015年的WWDC上,蘋果宣布Swift將會開放原始碼,不久後,在2015年的12月,Swift的code base即公開在 GitHub上。
這份公開的Swift 源始碼向全世界開發者介紹了Swift多面向的擴展應用,也讓世人見識到這個語言未來蘊藏的許多可能性。
就如預期一樣,開發者迅速開發出不同面向的Swift新應用,其中一項就是透過Swift語言去打造一個web app,我們將在接下來的篇幅去探索這個應用。
為什麼需要認識它?
如果你想幫自己的iOS app建置了後台,在伺服器上使用相同程式語言將會有很多優點,它可以比較容易維持程式碼風格的一致性。
目前已有三個很棒的Swift伺服器(server)端建置服務,包含:Perfect, Kitura以及 Vapor,本篇文章將會帶領讀者一起去探索Vapor,發掘使用Swift建置server的趣味世界。
接下來,本文將教你如何安裝Vapor以及Swift 3,並且使用Swift學習Server端的基礎應用,同時,也會展示如何將其部署到Heroku上,透過Swift建置你自己的後台。
開發前準備工作
在本文中,我們會使用很多的bash commands,因此,開發首要條件,就是對於基礎的bash指令以及終端機(Terminal)都要有基本認識,另外,Vapor是使用Swift 3進行開發,所以Xcode版本也要更新到8.0。
Vapor跟Swift(Swift Package Manager)專案必須使用Swift 3進行開發,所以建議讀者可以在這篇文章AppCoda 文章,學習Swift 3.0相關的語法變更,以利接下來的開發工作。
在這篇文章的最後,我將解釋如何在heroku上建置Vapor服務,heroku是著名的雲端平台服務提供者,本文會帶讀者初步認識它的使用方法。
現在開始進入本文重點!
安裝Vapor
Vapor需要使用到Swift 3以及Xcode最新版本 (Xcode 8 beta),你可以在這裡下載新版的Xcode。
首先,你必須選擇在Xcode指令列工具(command line tools),點擊Xcode preferences選項。
接著,請點開列表中的Locations選項。
最後,在Command Line Tools欄位點選Xcode 8,如下圖。
安裝Swiftenv
現在,該是安裝Swift 3的時候了,首先,請安裝Swiftenv,它讓開發者可以簡單安裝新的版本,並且輕易在各版本間進行轉換,讀者若尚未安裝Swiftenv,可以直接在Github上clone檔案進行安裝,請在終端機輸入下方圖片裡的程式碼。
git clone https://github.com/kylef/swiftenv.git ~/.swiftenv
緊接著,請在你存放相關設定的bash profile裡初始化Swiftenv,先在終端機輸入下方圖片中的指令,打開你的bash profile。
open ~/.bash_profile
open
這個指令將會打開你的bash profile進行文字編輯,如果你還沒有bash profile,可以輸入下方圖片中的指令進行創建。
touch ~/.bash_profile
當你打開你的bash profile後,請將下面圖片裡的這一段指令貼上,它將會幫你初始化Swiftenv。
export SWIFTENV_ROOT="$HOME/.swiftenv" export PATH="$SWIFTENV_ROOT/bin:$PATH" eval "$(swiftenv init -)"
你的bash profile(以編輯模式開啟)現在應該要包含上圖中那些指令,請注意,你的bash profile可能包含了其他的指令,不要去移除這些先前已經存在的指令,只要將上述需要新增的指令加在尾端即可。
儲存你的bash profile,並且重新開啟終端機,重新開始後,請輸入下方圖片的指令,確認Swiftenv是否已經成功安裝完成。
swiftenv --version
若已成功安裝,終端機將會出現像下方圖片訊息:
下載Swift 3 Snapshot
現在Swiftenv已經安裝完成,接下來,你必須去下載最新的Swift 3 Snapshot,在Swift package中,目前Swift Snapshot已經可供開發者下載安裝,請運行下方圖片指令。
swiftenv install 3.0-GM-CANDIDATE
它將會花一些時間去下載snapshot,當下載完成後,請在終端機將snapshot設置為Swift主要開發版本,輸入下方圖片裡的這一行程式碼,它將會讓開發者所有專案都適用這個設定。
swiftenv global 3.0-GM-CANDIDATE
輸入下圖這行程式碼,檢視3.0-GM-CANDIDATE
是否已設置完成。
swiftenv versions
你應該會看到一個星號在3.0-GM-CANDIDATE
旁邊。
Compatibility Checking
相容性檢查
Vapor需要搭配適當的Swift版本才能正確的運行,它提供一個shell script(程式化腳本)去協助你進行確認,請在終端機輸入下圖中的指令,看看設定是否出現問題。
curl -sL check.vapor.sh | bash
如果你看到一個綠色的打勾符號,就表示你已經完成安裝Vapor的相關設置。
安裝Vapor工具列
輸入下方圖片中的指令,下載安裝Vapor:
curl -sL toolbox.vapor.sh | bash
安裝可能需要一點時間,也可能會出現錯誤訊息,例如:"Install failed, trying sudo"
,但若是看到"Vapor Toolbox v0.10.4 Installed"
的訊息,表示你已經全部安裝完成。
若要檢查Vapor是否已經可以作業,請在終端機上輸入下列程式碼進行簡單的確認。
vapor
你應該會看到下圖顯示的訊息。
如果你也獲得相同的結果,恭喜你!你已經完成本篇教程中最具有挑戰性的一部份了。
開啟Vapor新專案
Swift Package Manager (SPM)是Swift專案中套件管理工具,每個SPM專案都有Package.json
以及main.swift
等檔案,這個專案會從Package.swift
中搜尋並下載需要用到的套件,它其實就像Node JS的NPM (Node Package Manager),在Vapor創立Swift專案時,請將開發時需要用到的套件名稱加到Package.swift
檔案裡面。
建立一個新的專案,你必須在Vapor替這個新專案命名,首先,請移動到希望創立這個新專案的目錄中,接著輸入下列這一行指令:
vapor new HelloWorld
Vapor將會在目前所在的目錄底下,建立一個名叫HelloWorld的專案,接下來,請移動到這個新專案的目錄底下,目錄的名稱就跟新建立的專案名稱一樣,請輸入下方程式碼進行這個動作:
cd HelloWorld
你應該會看到像是下面圖片中的目錄結構。
├── Package.swift ├── App │ ├── main.swift │ ├── Controllers │ ├── Middleware │ └── Models ├── Resources | └── Views ├── Config ├── Localization └── Public
Vapor遵從MVC架構(Model, View, Controller),它建立的專案已經分成Models,Views,Controllers三個不同資料夾,如果讀者對於MVC設計模式不太熟悉,可以點擊這裡獲得更多相關介紹。
首先,Vapor建立Package.swift
檔案,這裡不需要再去修改它,另外,也可以看到App
這個資料夾,裡面包含Models, Controllers, Middleware以及main.swift
檔案, main.swift是這個app重要文件,當我們初始化server的時候,Vapor將會先運行這個檔案。
另外,Views
資料夾放置在Resources
資料夾之中,裡面存放HTML
和template檔案, Public
則放置images和styles,其餘的資料夾我們目前不會用到。
The Droplet
Vapor會自動生成一個範例給我們,裡面包含 Controller, Model, Middleware以及main.swift
檔案,打開 main.swift
檔案,該檔案存放在/Sources/App路徑之下,請移除裡面所有程式碼。
Droplet是Vapor server的核心,它有大量的函式支援這個伺服器的運作。首先,將Vapor import到main.swift
檔案之中:
import Vapor
然後,生成一個Droplet
的物件,如下圖:
let drop = Droplet()
Droplet
有大量的可定制屬性,它能接受多個參數調用,詳細介紹請點擊Vapor Docs,在這個範例中,不需要去客製化我們的Droplet
。
現在,我們來處理網路請求(request),將主頁路徑設置為 '/'
:
drop.get("/") { request in return "Hello World!" }
最後,你需要呼叫serve()
這個函式來啟動server。
drop.serve()
請將main.swift
檔案儲存起來,並且在終端機輸入下圖中的指令,Vapor可以幫你建立並且運行這個server:
vapor build vapor run
Vapor沒有’專門’的操作指令,輸入vapor build
)與執行swift build
這行程式碼一樣,接著輸入 vapor run
將會在.build/debug/
目錄下運行已經build完成的程式碼。
這個操作可能會在首次執行時耗費一些時間,在建置成功後,你應該會看到如同下面圖片中所顯示的訊息:
Vapor預設在8080 port執行這個伺服器,如果讀者想要更改port,必須在configuration中修改servers.json
檔案:
├── Package.swift ├── App ├── Resources ├── Config | └── servers.json <-- ├── Localization └── Public
假設讀者沒有更改這個範例的port,就可以下面這個連結看到server的執行成果:
0.0.0.0:8080
或
localhost:8080
你應該可以看到"Hello World”這個令人熟悉的字串!
處理HTTP的請求
處理 HTTP
的請求與Express, Flask等框架類似,在本篇教程中,我們將會談論到GET
。
舉例來說,若是你想要在進入"localhost:8080/name/John"
時,顯示"Hello John!"
這個字串,請參考下列這串程式碼:
drop.get("/name",":name") { request in if let name = request.parameters["name"]?.string { return "Hello \(name)!" } return "Error retrieving parameters." }
我們的Droplet
有GET
處理函式get()
,get()
函式可以帶入多個參數,第一個參數是GET
請求的參數名稱,這個參數將會追隨一個 key
值。
drop.get("route", ":key", "route2", ":key2")
你可以輸入key
值發送一個請求,從dictionary型態參數中拿到對應的value
, key
必須在前方加上一個冒號,用來表示它為參數中的key值。
get()
函式提供我們一個request
物件,這個物件包含GET
所有請求方法,透過request
物件呼叫dictionary型態的parameters
,可以取得已經上傳的參數:
request.parameters["key"]
我們可以透過if let
語法來確保從這個參數有被賦值:
if let name = request.parameters["name"].string { // Do something }
這個HTTP請求需要取得伺服器的回應(response),response結果就是被呼叫函式的返回(return)值,在這個範例中,name
將會獲得一個字串的返回值,它是從我們dictionary型態的參數中取出。
嘗試去建立並執行這個專案,並且連結下列這個網址去測試這個GET請求:
http://localhost:8080/name/John
你應該會看到"Hello John!"這個訊息。
請注意,這個路由與Express等其他服務不同,在使用Vapor服務時,你不能以URI格式去存取參數:
http://localhost:8080/name?name=John&age=18
每個參數都必須在前方添加斜線區隔其他參數,如下圖:
http://localhost:8080/name/John/age/18
儘管如此,如果開發者還是習慣使用URI格式,可以透過request
物件的uri
屬性滿足你的需求,若想瞭解更多,可以參考request
物件的說明文件。
回傳指定畫面
我們的Droplet
可以依據客戶端的請求回傳一個view
,這個view
裡面包含一個HTML
檔,存放於/Resources/Views
資料夾裡面,點選這裡可以下載這個view.html
範例,它是一個非常簡易的HTML檔,呈現一個簡單的web頁面,在你下載完這個檔案後,移動到 /HelloWorld/Resources/Views這個路徑底下。
├── Package.swift ├── App ├── Resources | └── Views <-- ├── Config ├── Localization └── Public
這是Droplet
存放views的目錄,接下來,開始實作程式碼,打開main.swift
檔案,讓我們處理/view
的路由作業:
drop.get("/view") { request in return try drop.view("view.html") }
每個Droplet擁有一個view()
的函式,並帶有一個string
參數,它是我們 HTML
檔的名稱。
這個view()
的函式有做throws an exception(例外處理),因此,必須使用 try
去標記它,如果這個view並不存在,該函式將會拋出異常訊息,而開發者可以用catch
去獲取錯誤訊息,但是此範例並不會用到,因為我們已經知道這個檔案存在。
Let's build and run:
vapor build vapor run
現在請進入下列這個連結:
http://localhost:8080/view
現在你應該可以看到網頁顯示”Hello World”字串,讀者可以在the documentations中獲得更多Templating和Rendering資訊。
Heroku部署
Heroku可以協助開發者建立並且管理Swift專案,這是部署你的Vapor專案最好且最簡單的方式,本文預設讀者對於Heroku已有基本認識,你可以使用Heroku toolbelt去部署這個專案,但是在這裡,我們將會把這個專案push到Github上面,並且將Heroku與Github進行連結。
首先,我們先在Github創立一個新的repository,這邊將會把我的repository命名為VaporExample,請移動到Vapor專案的目錄底下,並且在這邊進行git初始化的作業:
git init
下一步,我們將會設定remote origin路徑:
git remote set origin < Your Github Repo Here >
接下來,依序進行Add, commit,並將它push到Github之上:
git add . git commit -m "Init" git push -u origin master
現在我們已經完成push的工作,現在前往你的Heroku dashboard,創立一個新的app並對它命名,建立完成後進到設定頁面。
再來,請將頁面向下滑動至"Buildpacks”選項。
接著,將這個連結https://github.com/kylef/heroku-buildpack-swift
添加到Buildpack欄位中,它會建立你的Swift專案,並且告知Heroku是使用什麼語言。
下一步,請移動到部署的選項。
將你的Deployment method變更到GitHub上面,並且將GitHub Repository的名稱新增至這個app,讓Heroku將你的Repository加入到這個專案內,接下來將這個頁面向下滑動至Manual Deploy的欄位,並點擊Deploy Branch進行部署,這個動作可能會需要一些時間。
完成建置後,可以前往Heroku提供的連結頁面查看你的網站!
結論
本文中我們介紹了如何安裝Vapor,以及用Swift的建立server,並將它部署在Heroku之上。第一步,我們必須安裝Xcode 8,接著安裝Swiftenv以便於下載安裝Swift 3,然後安裝Vapor工具列,並且示範基本的路由實作和處理HTTP請求,以及根據請求返回對應的views,最終,也學習到如何將你的Vapor server部署到Heroku上。
相較於其他Swift server應用,我還是偏好Vapor,它是最實用且操作簡易的服務。IBM的Kitura是單一dependency,迫使你必須在這裡去引用外部的Swift dependencies,但因為不是由自已的團隊更新相關服務,因此造成很大的問題,另一方面,Perfect在使用上感覺太過繁雜,Vapor使用起來較為簡潔。
Vapor擁有很多不同的功能,本文中僅帶領讀者認識基本的用法,若想瞭解更多,可以前往Vapor documentations,相關文件有更多的功能介紹,包含下列幾項:
- 支援相關模組: 像是 handlebars 或是 angular。
- 資料庫模型: SQL, noSQL, Mongo等,只要你講得出,Vapor幾乎都有支援。
- Sockets: Vapor使用web sockets達到即時溝通的效果。
- JSON 序列化: 像是 SwiftyJSON。
- MVC 模式: 能夠去建立 Controllers和Models。
- Middlewares: 可以增加任何參數到HTTP requests,對於APIs是非常實用的.
- Hashing: Vapor幾乎可以依據開發者需求創建任何hash值。
另外還有更多無法詳列於此
希望你可以享受這篇Vapor基礎教程,點擊這個GitHub可下載完整的專案,另外,也可以在這裡查閱Vapor創辦人提供的多個範例。
FB : https://www.facebook.com/yishen.chen.54
Twitter : https://twitter.com/YeEeEsS