#41 訂飲料 APP | Part3 建立 飲料訂單並上傳至 AirTableAPI
建立 飲料訂單,使用RESTFul API “POST”的建立資料功能,將飲料訂單上傳到 AirTable API
Published in
16 min readJul 2, 2022
Part 2. 的時候,已經建立了OptionViewController,也已經建立了@IBSegueAction 來將資料從MenuTableViewController 傳到OptionViewController。
現在先來設計OptionViewController頁面。
- nameLabel 為從MenuTableViewController傳過來的飲料名稱。
- drinkImageView 為從MenuTableViewController傳過來的飲料圖片。
- orderTextField 為訂構者姓名,按送出訂單之後就會上傳到 AirTable。
- 溫度(temperatureChoice)跟甜度(sweetChoice)直接使用UISegmentedControl來傳送選項。
- 杯型跟加料因為需要加錢,所以需要拉@IBOutlet 跟@IBAction。
- priceLabel 為計算總價格。
- 送出訂單 Button 就是將以上的選項上傳至 AirTable。
設定一開始顯示的資料
加入以下程式碼,讓頁面一開始就顯示上一頁傳過來的飲料選項,還有其他選項的預設值。
// 選項預設值
var cupSize = "中杯"
var temperature = "正常冰"
var sweet = "正常糖"
var topping = "不加料"
var finalPrice = ""// 頁面一開始顯示的資料 function
func updateUI() {
// 如果沒有大杯的價格,杯型選取的功能就不出現
if drinkMenu.fields.largePrice == nil {
sizeSegment.isEnabled = false
}
nameLabel.text = drinkMenu.fields.drinkName
priceLabel.text = drinkMenu.fields.mediumPrice
finalPrice = drinkMenu.fields.mediumPrice
//顯示飲料圖片,利用 URLSession 下載圖片
URLSession.shared.dataTask(with: drinkMenu.fields.drinkImage[0].url) { data, response, error in
if let data = data {
DispatchQueue.main.async {
self.drinkImageView.image = UIImage(data: data)
}
}
}.resume()
}
UISegmentedControl 的內容設定
- 溫度(temperatureChoice)跟甜度(sweetChoice)直接使用UISegmentedControl來傳送選項。因為沒有加錢,比較簡單,就讓選好的選項記住就好。
利用 Switch 來決定使用者的選擇。
@IBAction func temperatureChoice(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
temperature = "正常冰"
case 1:
temperature = "少冰"
case 2:
temperature = "微冰"
case 3:
temperature = "去冰"
case 4:
temperature = "溫熱"
default:
break
}
}
@IBAction func sweetChoice(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
sweet = "正常糖"
case 1:
sweet = "少糖"
case 2:
sweet = "半糖"
case 3:
sweet = "微糖"
case 4:
sweet = "無糖"
default:
break
}
}
- 杯型跟加料因為需要加錢,程式碼比較複雜。
因為加杯型加大或加白玉都需要加 10元,所以在杯型的選項中,需要加入是不是有加選白玉的價格,在加白玉的選項中,需要加入是中杯還是大杯的價格。如下:
@IBAction func cupSizeChoice(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
cupSize = "中杯"
if toppingSegment.selectedSegmentIndex == 0 {
finalPrice = drinkMenu.fields.mediumPrice
} else {
let mediumPrice = drinkMenu.fields.mediumPrice
finalPrice = String(Int(mediumPrice)! + 10)
}
priceLabel.text = finalPrice
case 1:
cupSize = "大杯"
if toppingSegment.selectedSegmentIndex == 0 {
finalPrice = drinkMenu.fields.largePrice ?? ""
} else {
let largePrice = drinkMenu.fields.largePrice ?? ""
finalPrice = String(Int(largePrice)! + 10)
}
priceLabel.text = finalPrice
default:
break
}
}@IBAction func toppingChoice(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
topping = "不加料"
if sizeSegment.selectedSegmentIndex == 0 {
finalPrice = drinkMenu.fields.mediumPrice
priceLabel.text = finalPrice
} else if sizeSegment.selectedSegmentIndex == 1 {
finalPrice = drinkMenu.fields.largePrice ?? ""
priceLabel.text = finalPrice
}
case 1:
topping = "白玉"
if sizeSegment.selectedSegmentIndex == 0 {
finalPrice = String(Int(drinkMenu.fields.mediumPrice)! + 10 )
priceLabel.text = finalPrice
} else if sizeSegment.selectedSegmentIndex == 1 {
let largePrice = drinkMenu.fields.largePrice ?? ""
finalPrice = String(Int(largePrice)! + 10)
priceLabel.text = finalPrice
}
case 2:
topping = "水玉"
if sizeSegment.selectedSegmentIndex == 0 {
finalPrice = String(Int(drinkMenu.fields.mediumPrice)! + 10 )
priceLabel.text = finalPrice
} else if sizeSegment.selectedSegmentIndex == 1 {
let largePrice = drinkMenu.fields.largePrice ?? ""
finalPrice = String(Int(largePrice)! + 10)
priceLabel.text = finalPrice
}
default:
break
}
}
在 AirTable 建立orderList 的 Table,來儲存 APP 上傳的資料
總共有 7 個資料要寫入
- name
- drinkName
- cupSize
- temperature
- sweet
- topping
- finalPrice
一樣在程式端這邊也要建立一個OrderList 的型別,OrderList.swift
import Foundationstruct OrderList: Codable {
let records: [Type]
}struct Type: Codable {
let id: String?
let fields: Option
}struct Option: Codable {
let name: String
let drinkName: String
let temperature: String
let sweet: String
let topping: String
let finalPrice: String?
let cupSize: String
}
來看一下 AirTable API POST 的寫法
- -X 就是
httpMethod = “POST”
- -H 就是 HTTP header
request.setValue("Bearer API-KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
- -d 或 — data 就是上傳的資料
let user = OrderList(records: [.init(id: nil, fields: .init(name: orderTextField.text!, drinkName: drinkMenu.fields.drinkName, temperature: temperature, sweet: sweet, topping: topping, finalPrice: finalPrice, cupSize: cupSize))])let data = try? encoder.encode(user)
request.httpBody = data
上傳選項到 AirTable 建立一筆新的資料
@IBAction func placeOrder(_ sender: Any) {
if orderTextField.text?.isEmpty == true {
let alertController = UIAlertController(title: "", message: "請輸入訂購者姓名", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true)
} else {
if let url = URL(string: "https://api.airtable.com/v0/appbQTpLmlKHdXTtu/orderList") {
var request = URLRequest(url: url)
request.setValue("Bearer API-KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let encoder = JSONEncoder()
let user = OrderList(records: [.init(id: nil, fields: .init(name: orderTextField.text!, drinkName: drinkMenu.fields.drinkName, temperature: temperature, sweet: sweet, topping: topping, finalPrice: finalPrice, cupSize: cupSize))])
let data = try? encoder.encode(user)
request.httpBody = data
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
do {
let decoder = JSONDecoder()
let orderList = try decoder.decode(OrderList.self, from: data)
print(orderList.records.count)
} catch {
print(error)
}
}
}.resume()
}
let orderSuccessController = UIAlertController(title: "", message: "已完成訂購", preferredStyle: .alert)
orderSuccessController.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
self.navigationController?.popViewController(animated: true)
}))
present(orderSuccessController, animated: true)
}
}
程式說明如下:
- 這邊有加了一個檢查,如果orderTextField 裡面是空字串的話,就會跳出 alert 警告。如果有輸入名字,就會繼續程式進行~
if orderTextField.text?.isEmpty == true {
let alertController = UIAlertController(title: "", message: "請輸入訂購者姓名", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true)
}
2. 檢查完名字輸入完成之後,就會執行下段程式。
利用 RESTful API 的 POST 功能,將在這個頁面的資料上傳到 AirTAble。
if let url = URL(string: "https://api.airtable.com/v0/appbQTpLmlKHdXTtu/orderList") {
var request = URLRequest(url: url)
request.setValue("Bearer API-KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let encoder = JSONEncoder()
let user = OrderList(records: [.init(id: nil, fields: .init(name: orderTextField.text!, drinkName: drinkMenu.fields.drinkName, temperature: temperature, sweet: sweet, topping: topping, finalPrice: finalPrice, cupSize: cupSize))])
let data = try? encoder.encode(user)
request.httpBody = data
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
do {
let decoder = JSONDecoder()
let orderList = try decoder.decode(OrderList.self, from: data)
print(orderList.records.count)
} catch {
print(error)
}
}
}.resume()
}
3. 上傳資料到 AIrTable 之後,會跳出一個 Alert 說明“已完成訂購”,然後回到菜單頁面~
let orderSuccessController = UIAlertController(title: "", message: "已完成訂購", preferredStyle: .alert)
orderSuccessController.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
self.navigationController?.popViewController(animated: true)
}))
present(orderSuccessController, animated: true)
}
結果如下