#17— 飲料訂購APP_Part2|串接Airtable API下載、上傳、刪除資料

呈現畫面:

透過利用 Airtable 製作 iOS App 連結的後台資料,就可達到練習GETPOSTPATCH/ PUT(修改此篇未使用)以DELETE的功用,讓我來一一講解,但在此之前必須先建立自己的表單才能發揮它的作用。

我先做了一個飲品Menu的表單,內容包含飲料名稱、價格、圖片網址、是否能做熱飲等等,我這裡多做了一個編號(為了排列順序,後來想想應該直接給飲品分類名稱比較適當),如下圖

(Airtable API 提供豐富的參數讓我們調整,加入 sort 控制資料的排序)

https://api.airtable.com/v0/appjAvWZDqTgRklgL/Drink?sort[][field]=number&sort[][direction]=asc

如此以來抓到的資料順序就會是小到大的編號,可以從Postman輸入看看

從Airtable 的 API 網頁可看到自己設定的表格串接介紹

第一頁飲品Menu製作:

自定義的資料型別(資料不一定有的情況,型別記得加上問號,例如我這裡不一定能加奶蓋,所以奶蓋價格不一定有)

將解析JSON的Decoder寫在自定義的Function裡

(為了將飲品分類到不同Section,我這裡用了比較笨的方法)

var drink = [DrinkMenu.Records]()var drink1 = [DrinkMenu.Records]()
var drink2 = [DrinkMenu.Records]()
var drink3 = [DrinkMenu.Records]()
var drink4 = [DrinkMenu.Records]()
var drink5 = [DrinkMenu.Records]()
var total = [[DrinkMenu.Records]]()
var category = ["果然好韻","好韻那堤","在地好韻","好韻特調","醇韻奶香"]
func fetchDrinkMenu(){
let urlStr = "https://api.airtable.com/v0/appjAvWZDqTgRklgL/Drink?sort[][field]=number&sort[][direction]=asc"
if let url = URL(string: urlStr) {
var request = URLRequest(url: url)
request.setValue("Bearer 你的API key", forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { [self] data, response, error in
let decoder = JSONDecoder()
if let data = data {
do{
let drinkMenu = try decoder.decode(DrinkMenu.self, from: data)
self.drink = drinkMenu.records
for i in 0...8{
drink1.append(drink[i])
}
for i in 9...16{
drink2.append(drink[i])
}
for i in 17...20{
drink3.append(drink[i])
}
for i in 21...26{
drink4.append(drink[i])
}
for i in 27...31{
drink5.append(drink[i])
}
total = [drink1,drink2,drink3,drink4,drink5]
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print(error)
}
}
}.resume()
}
}

點擊TableViewCell會觸發segue並傳遞資料,資料包含選擇cell的section、row

從程式加上一個Button方便我們點擊觸發產生全部訂單畫面

let buttonToShoppinglist = UIButton()
buttonToShoppinglist.translatesAutoresizingMaskIntoConstraints = false
tableView.addSubview(buttonToShoppinglist)
buttonToShoppinglist.heightAnchor.constraint(equalToConstant: 50).isActive = true
buttonToShoppinglist.widthAnchor.constraint(equalToConstant: 100).isActive = true
buttonToShoppinglist.trailingAnchor.constraint(greaterThanOrEqualTo: tableView.safeAreaLayoutGuide.trailingAnchor, constant: -30).isActive = true
buttonToShoppinglist.bottomAnchor.constraint(greaterThanOrEqualTo: tableView.safeAreaLayoutGuide.bottomAnchor, constant: -30).isActive = true
buttonToShoppinglist.setTitle("訂單", for: .normal)
buttonToShoppinglist.tintColor = .white
buttonToShoppinglist.backgroundColor = .black
buttonToShoppinglist.setImage(UIImage(systemName: "cart.fill"), for: .normal)
buttonToShoppinglist.layer.cornerRadius = 20
buttonToShoppinglist.addTarget(self, action: #selector(showList), for: .touchUpInside)
//點擊button觸發的function
@objc func showList(){
if let controller = storyboard?.instantiateViewController(withIdentifier: "OrderListViewController") {
present(controller, animated: true, completion: nil)
}
}

第二頁飲品訂單上傳:

同樣先製作一個新的表單用來記錄飲品的詳細內容,在這我設定了使用者姓名、飲料名稱、價格、甜度、冰塊、加料、全部總金額、杯數最後是使用者圖片網址

同樣從Airtable 的 API 網頁找到串接方法,這次是POST!

自定義的資料型別(這裡我重複利GET的struct DrinkOrder,差別在於上傳時不需要用到id,所以id的型別加上問號,設定上傳資料時id設為nil即可)

這裡我多定義了一個Class dataForOrderPost,為了暫存使用者所點選的內容,方便最後一起上傳

同樣將上傳內容寫在自定義的Function裡

(這裡順邊將Firebase用戶網址上傳至Airtable)

//上傳訂單資料
func orderPost(){
//Firebase獲取用戶圖片網址
if let user = Auth.auth().currentUser {
pic = user.photoURL
print("\(String(describing: user.photoURL))123")
}
//總金額乘上杯數
let totalMoney = (mikeCapMoney + addMoney)*Int(stepperOutlet.value)

let order = DrinkOrder(records: [.init(id: nil, fields: .init(orderName: dataForOrderPost.orderName, drinkName: dataForOrderPost.drinkName, mikeCap: dataForOrderPost.mikeCap, drinkSuger: dataForOrderPost.drinkSuger, drinkIce: dataForOrderPost.drinkIce, add: addStr, total: totalMoney, cups: Int(stepperOutlet.value),pic:pic))])

let urlStr = "https://api.airtable.com/v0/appjAvWZDqTgRklgL/OrderDrink"
if let url = URL(string: urlStr){
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()
request.httpBody = try?encoder.encode(order)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
//印出上傳資料data
let content = String(data: data, encoding: .utf8)
print(content ?? "123")
}
}.resume()
}
}

(成功上傳可以看到Airtable資料新增)

比較特別的是tableView的didSelectRowAt、didDeselectRowAt,這兩項顧名思義一個代表點擊會觸發、另一個代表取消點擊會觸發,就看自己想要怎樣的效果就寫在裡面,我就不贅述了。

而讓 table view cell多選,而且每個 section 只能選一個 cell 的功能,可以參考peter文章

結果:

最後送出訂單或回上一頁時,把暫存在Class dataForOrderPost的資料清空

第三頁飲品訂單製作:

最後一頁比較特別,用了ViewController+Collection View+Table View,Collection View單純只是為了顯示無限輪播的分頁圖片,而Table View則是顯示Airtable的訂單表單。

上一篇IG內容是要將照片分為手機寬度的三分之一,但這次我要顯示的只有一張圖片,所以大小就是我UI上拉的Collection View大小,再搭配CollectionView.scrollToItem、Timer.scheduledTimer重複計時達到無限輪播的功能。

再來Table View的部分就如同第一頁,抓取訂單表格作法一樣,只是這裡要額外抓取id,因為我們需要id來做刪除資料的功能

自定義的資料型別

將解析JSON的Decoder寫在自定義的Function裡

var orderList = [DrinkOrder.Records]()//抓取訂單資料
func fetchOrderLest(){
let urlStr = "https://api.airtable.com/v0/appjAvWZDqTgRklgL/OrderDrink"
if let url = URL(string: urlStr){
var request = URLRequest(url: url)
request.setValue("Bearer 你的API key", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
let decoder = JSONDecoder()
if let data = data {
do{
let orderList = try decoder.decode(DrinkOrder.self, from: data)
self.orderList = orderList.records
for i in self.orderList{
self.totalMoney += i.fields.total
}
DispatchQueue.main.async {
self.ListTableView.reloadData()
}
}catch{
print(error)
}
}
}.resume()
}
}

最後就是資料刪除的部分

用API的網址後面帶入訂單的ID即可,同樣寫在自定義的Function裡

//刪除airTable訂單
func deleteOrderList(urlStr:String){
if let url = URL(string:"https://api.airtable.com/v0/appjAvWZDqTgRklgL/OrderDrink/\(urlStr)"){
var request = URLRequest(url: url)
request.setValue("Bearer 你的API key", forHTTPHeaderField: "Authorization")
request.httpMethod = "DELETE"
URLSession.shared.dataTask(with: request) { data, response, error in
if error == nil{
print("成功")
}else{
print(error ?? "失敗")
}
}.resume()
}
}

搭配tableView(_ , commit , forRowAt)就可以完成刪除動作(記得把Airtable抓下來的資料陣列也刪除)

結果:

參考資料:

--

--

Responses (1)