Swift 專案 #10 訂飲料App-1 (GET\POST)
製作動機:彼得潘最知名的大型活動,潘大請飲料,在請之前要先自己寫出訂飲料的 App 出來,雖然說全班只要有一個人寫出來就喝得到飲料了,但怎麼能這麼沒出息,在一上完課後立馬開始著手進行開始作業。
主要重點描述功能:
- 製作後台的工具網站 Airtable。
- JSON 的串接,包含下載資料的 GET 以及 上傳新建資料的 POST。
- 網頁連線測試工具,postman 以及 終端機 curl。
問題一:Airtable他是拿來幹嘛的? 如何建立資料庫?
這是一個強大的資料庫管理網站,可以支援包含 google 以及微軟的各式表格,這次我們要使用到的事他們的專案管理功能以建立一個飲料資料的後台,並且經由這個後台我們會將資料從上面下載下來,在 App 執行使用期間,也會把所需要的資料上傳至後台。
因為建立資料庫潘大一樣寫得很清楚了,所以就把他請出來吧。
問題二:如何使用 Airtable 所提供的 API。
在建立好的 table 頁面中,我們點選右上角的使用者,會出現圖中方框,裏面便有 Developer hub 的選項,點下去進到下個頁面。
進去後點選左邊的 API Key 即可看到下方他把你的私鑰用加密的方式放在下面了,記得要保管好不要隨便給別人,後續串接都需要用到。
另外,API Key 上面有一個 token,之後應該會換成這個做認證,以目前來說用哪個都可以。
在看到左邊有個選項是 Web API documentation,點進去後會看到下圖頁面,下面顯示的 My First Workspace 就是我們現在有的專案,點進去之後裡面會給予詳細有關於串接這個網站的資訊。
問題三:如何取用建立好的資料庫到程式碼中?
要將網路資料庫下載到程式碼中我們將利用上次串接 url 講過的方法,在這邊我們先講解一下 串接 API 主要是用四個 Method,GET\POST\PATCH\DELETE ,而下載多半會使用 GET 這個功能。
在剛剛說的裡面會看到他提供這樣子的範例給你看,每個人都會有不同的 ID 以及 table 名稱,所以這串網址都會不同,下方則是你需要提供給他的 HTTPHEAD,也就是這邊需要你提供一個你的 API KEY 或 Token 的 value,給名叫 Authrization 的 key。
再講清楚一點我們到終端機看一下。
像這樣把你的 URL 跟 API Key 打到終端機上就會出現你所建立的資料庫的 JSON 了。
或是我們到另一個測試的工具網頁 postman 上看看。
紅色方框內我們選擇 GET,並且在下方的 Authorization 給予我們的 key-value 型態的 Api key,請留意左邊 Type 的地方要選擇一下,若你是用 Api key 的人就選 Api Key,使用 Token 的話也要換成 Token 喔。
至於 value 最前面的 Bearer 貌似要不要加都可以。
若成功的話下面則會跑出你所建立的資料庫中的 JSON 資料了,若是成功的話就可以用在程式碼上面了。
程式碼中其實與上次所使用的方式並無差異,所以大致功能請參照上次的文章,一樣先行建立 JSON 格式所要使用的 Model,這裡稍微比較不一樣的是上一片沒有使用到 API Key,於是程式碼改為以下。
func fetchGetData(){
let kebukeURLString = "https://api.airtable.com/v0/app8qDE2IVOV4sQFh/kebuke".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
if let url = URL(string: kebukeURLString){
var request = URLRequest(url: url)
request.setValue("Bearer key......", forHTTPHeaderField: "Authorization")
// print(request)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data,
let content = String(data: data, encoding: .utf8){
do {
let result = try JSONDecoder().decode(Records.self, from: data)
self.kebukeMenu = result.records
DispatchQueue.main.async {
self.kebukeTableView.reloadData()
}
// print(content)
} catch {
print(error)
}
}
}.resume()
}
}
我們將 URLRequest 儲存成名為 request 的變數,並且對他使用 setValue 將 API Key 加進去,基本上就能夠順利讀到檔案了。
問題四:如何上傳資料至後台 Airtable 呢?
首先我們上傳的資料庫希望在 Airtable 中放在另一個 table,於是我們先建立一個新的 table。
像這樣把我們想要上傳的資料屬性都建立起來,因為還沒上傳東西所以是空的,等等我們就會把訂單選好的飲料傳到這裡來摟。
新增資料至網路我們將使用到 POST 這項方法,與下載方式大同小異,我們先看程式碼。
func postFetch(){
// 將選好的飲料內容儲存到預先建立好的變數中,以達到符合上傳的JSON格式的 Model。
uploardField = OrderBody(fields: addShopCart)
// 此為專屬 for 儲存訂購飲料的後台 table 網址,與儲存全部飲料的菜單網址不同,但專案 ID api_key 是同一個。
let urlString = "https://api.airtable.com/v0/app8qDE2IVOV4sQFh/kebukeOrderList"
if let url = URL(string: urlString){
var request = URLRequest(url: url)
// apiKey認證
request.setValue("Bearer keyTaDO1pC3Wi8kV3", forHTTPHeaderField: "Authorization")
// httpMethod 設定
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
// 將內容加入 httpBody
request.httpBody = try? JSONEncoder().encode(uploardField)
// URLSession 本身還是必須執行,為主要上傳功能。
URLSession.shared.dataTask(with: request) { data, response, error in
//// 內容單純拿來檢查矩陣內容,與上傳並無關係
// if let data = data,
// let content = String(data: data, encoding: .utf8) {
// print(content)
// }
}.resume()
}
}
主要差異:
- 因為我們是要上傳資料,像 GET 一樣我們需要間建立一個符合 JSON 格式的變數去儲存下載下來的資料,對指定 URL 下載下來的資料做 “解碼”後放進去,POST 這邊就是我們要先把要上傳的資料先建立成符合我們上傳的 JSON 格式,進行 “編碼” 後再丟到網路上。
- 除了 API Key 之外他還需要設定另外的資料,以這個例子來說,他有指定我們需要加入另一個 HTTPHEAD “Content-Type : application/json”,這是上傳資料的其中一種格式類型。
3. 我們需要另外設定 HttpMethod,之前沒有特別設定將會默認為 GET,所以這次要另外給予指定屬性為 POST。
request.httpMethod = "POST"
4. 將我們的資料編碼過後,加入 httpbody 之中。
request.httpBody = try? JSONEncoder().encode(uploardField)
5. 最後一樣利用 URLSession 來進行任務。
// URLSession 本身還是必須執行,為主要上傳功能。
URLSession.shared.dataTask(with: request) { data, response, error in
//// 內容單純拿來檢查矩陣內容,與上傳並無關係
// if let data = data,
// let content = String(data: data, encoding: .utf8) {
// print(content)
// }
}.resume()
順利的話這樣資料應該就會被傳入 Airtable 中了。
這邊一樣可以使用 postman 或是 curl 來進行測試,成功了再來真的進行程式碼的編輯也可以喔,類似下圖,將對應好格式的資料貼上去,也可以檢查看自己的格式是否正確。
部分畫面功能備註:
- 下拉式 Button,在按下按鈕後會出現指定選項,這邊按下按鈕後會根據不同的資料來顯示成為 Button 的 Title,再將背景製作成像 TextField 的大小般,看起來像是有下拉選單功能並且會自動填入文字的 TextField。
func sugarButtonSet(){
let rowNum = allDrinks[indexPathRowNum].fields.sugar
sugarButtonOutlet.menu = UIMenu(children: [
UIAction(title: rowNum[0], handler: { action in
self.sugarChoose = rowNum[0]
self.addShopCart.sugar = rowNum[0]
self.sugarButtonOutlet.setTitle(self.sugarChoose, for: .normal)
}),
UIAction(title: rowNum[1], handler: { action in
self.sugarChoose = rowNum[1]
self.addShopCart.sugar = rowNum[1]
self.sugarButtonOutlet.setTitle(self.sugarChoose, for: .normal)
}),
UIAction(title: rowNum[2], handler: { action in
self.sugarChoose = rowNum[2]
self.addShopCart.sugar = rowNum[2]
self.sugarButtonOutlet.setTitle(self.sugarChoose, for: .normal)
}),
UIAction(title: rowNum[3], handler: { action in
self.sugarChoose = rowNum[3]
self.addShopCart.sugar = rowNum[3]
self.sugarButtonOutlet.setTitle(self.sugarChoose, for: .normal)
}),
UIAction(title: rowNum[4], handler: { action in
self.sugarChoose = rowNum[4]
self.addShopCart.sugar = rowNum[4]
self.sugarButtonOutlet.setTitle(self.sugarChoose, for: .normal)
})
])
}
2. 沒有填入訂購者不給訂:因為不管是要收錢還是要給飲料,沒有訂購者都很麻煩,所以加入了這個功能,沒有輸入以及訂購完成都會顯示 Alert ,順帶一提,若沒有選擇甜度冰塊的話,會默認為正常甜正常冰,容量則為中杯。
@IBAction func addChooseList(_ sender: UIButton) {
if let orderHumanName = orderHumanTextField.text,
let price = addShopCart.price{
if orderHumanName != ""{
addShopCart.human = orderHumanName
postFetch()
//加入成功加入的alert
let controller = UIAlertController(title: "已加入購物車", message: "記得付$\(price)", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default)
controller.addAction(action)
present(controller, animated: true)
}
// 出現alert請填寫訂購者稱呼
let controller = UIAlertController(title: "請輸入訂購者", message: "不輸入就不用喝了", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default)
controller.addAction(action)
present(controller, animated: true)
}
}
目前結帳畫面是使用 GET 來把上傳過去的資料再下載回來,步驟就跟之前一樣,以上是第一階段的紀錄,下次要將一些顯示的細節,飲料加料以及修改、刪除等功能加入。
2023/04/24
製作時間約 : 2 Days