iOSで簡易コーポレートサイト（アプリ）を作成する #3 -API連携編-

# 概要
SwiftでAPIと連携を実装します。
JSONレスポンスを取得して画面上に表示できるように設定します。

# API連携
ContactFormViewに戻って送信ボタンをクリックしたときの動作を設定していきます。
Buttonにactionを追加していきます。

APIのURL、Method、Header、httpBodyの設定を行って、URLSessionを使ってデータ転送処理を行います。
転送でエラーが返ってきた場合の処理を記述します（コンソールにエラーを表示）。
また、レスポンスがステータスコード200以外もエラーなので、200以外が返ってきた場合の処理を記述しておきます（コンソールにエラーを表示）。
そうでなければ、APIのreturnがjsonで返ってくるのでそれをコンソールに表示させるようにします。

```diff_swift:ContactFormView.swift
	                Button(action:{
+	                    let url = URL(string:"https://script.google.com/macros/s/{デプロイID}/exec")!
+
+	                    var request = URLRequest(url: url)
+
+	                    request.httpMethod="POST"
+	                    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
+	                    request.httpBody="name=\(CFVM.name)&&email=\(CFVM.email)&&body=\(CFVM.contactBody)".data(using:.utf8)
+
+	                    let task = URLSession.shared.dataTask(with: request) { data, response, error in
+
+	                        if let error = error {
+	                            print("クライアントエラー: \(error.localizedDescription) \n")
+	                                    return
+	                        }
+	                        guard let data = data, let response = response as? HTTPURLResponse else {
+	                          print("データがありませんでした。")
+	                          return
+	                        }
+
+	                        
+	                        if response.statusCode == 200 {
+	                            do{
+	                                let result = try JSONSerialization.jsonObject(with: data) as! Dictionary<String,Any>
+	                                print(result["message"] as! String)
+	                            }catch{
+	                                print("ERROR")
+	                            }
+	                            
+	                        }
+	                       
+	                    }
+	                    task.resume()
	                }){
	                    Text("送信")
	                        .frame(minWidth: 160)
	                        .foregroundColor(.white)
	                        .padding(12)
	                        .background(Color.accentColor)
	                        .cornerRadius(8)
	                }	                            
```

```swift:コピペ用
let url = URL(string:"https://script.google.com/macros/s/{デプロイID}/exec")!

var request = URLRequest(url: url)

request.httpMethod="POST"
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody="name=\(CFVM.name)&&email=\(CFVM.email)&&body=\(CFVM.contactBody)".data(using:.utf8)

let task = URLSession.shared.dataTask(with: request) { data, response, error in

    if let error = error {
        print("クライアントエラー: \(error.localizedDescription) \n")
                return
    }
    guard let data = data, let response = response as? HTTPURLResponse else {
      print("データがありませんでした。")
      return
    }

    
    if response.statusCode == 200 {
        do{
            let result = try JSONSerialization.jsonObject(with: data) as! Dictionary<String,Any>
            print(result["message"] as! String)
            
        }catch{
            print("ERROR")
        }
        
    }
   
}
task.resume()
```

## 確認
できたら、確認してみます。
実際の動作確認は、Viewを確認するだけではできないためエミュレータを立ち上げて実行します。
エミュレータを立ち上げて、Contactをクリックし、値を正しく（APIのバリデーションに引っかからないように）入力して送信ボタンをクリックすると「success!」が返ってきているのがわかります。
<img width="1826" alt="000001.jpg" src="https://dl.dropbox.com/s/538nc4vada7bt6d/000001.jpg">

APIと連携はできるようになりました。
今、コンソールに表示しているメッセージを画面上部に表示させるようにしてみます。
初期値が空のmessageを用意し、messageが空でなかったらTextを表示するようにします。

```diff_swift:ContactFormView.swift
    struct ContactFormView: View {
        
        @ObservedObject var CFVM = ContactFormViewModel()
        
+       @State var message = ""
        
        var body: some View {
            VStack{
                Text("Contact").font(.title)
                
+               VStack{
+                   if message != "" {
+                       Text("\(message)")
+                            .frame(maxWidth:.infinity)
+                            .frame(height:50)
+                            .background(.blue)
+                            .foregroundColor(.white)
+                   }
+               }
                                
                VStack{
                    Text("お問合わせフォーム").font(.headline).foregroundColor(.white)
                }
                .frame(maxWidth:.infinity)
                .frame(height:100)
                .background(.blue)
```
```swift:コピペ用
VStack{
    if message != "" {
        Text("\(message)")
             .frame(maxWidth:.infinity)
             .frame(height:50)
             .background(.blue)
             .foregroundColor(.white)
    }
}
```
messageの値は、ボタンをクリックしたあとの「success!」をコンソールにprintしていた部分で設定します。

```diff_swift:ControlFormView.swift
    Button(action:{

        let url = URL(string:"https://script.google.com/macros/s/{デプロイID}/exec")!

        var request = URLRequest(url: url)

        request.httpMethod="POST"
        request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpBody="name=\(CFVM.name)&&email=\(CFVM.email)&&body=\(CFVM.contactBody)".data(using:.utf8)

        let task = URLSession.shared.dataTask(with: request) { data, response, error in

            if let error = error {
                print("クライアントエラー: \(error.localizedDescription) \n")
                        return
            }
            guard let data = data, let response = response as? HTTPURLResponse else {
              print("データがありませんでした。")
              return
            }

            
            if response.statusCode == 200 {
                do{
                    let result = try JSONSerialization.jsonObject(with: data) as! Dictionary<String,Any>
-                   print(result["message"] as! String)
+                   self.message = "\(result["message"] as! String)"
                   
                }catch{
                    print("ERROR")
                }
                
            }
           
        }
        task.resume()
```
保存して動作確認をしてみます。
送信ボタンをクリックすると上部にメッセージが表示されます。
<img width="300" alt="000010.jpg" src="https://dl.dropbox.com/s/ym7s26gfo11ifig/000010.jpg">

# 最終的なコード
## 
```swift:ContactFormView
import SwiftUI

struct ContactFormView: View {
    @ObservedObject var CFVM = ContactFormViewModel()
    @State var message = ""
    
    var body: some View {
        VStack{
            Text("Contact").font(.title)
            VStack{
                if message != "" {
                    Text("\(message)")
                         .frame(maxWidth:.infinity)
                         .frame(height:50)
                         .background(.blue)
                         .foregroundColor(.white)
                }
            }
                            
            VStack{
                Text("お問合わせフォーム").font(.headline).foregroundColor(.white)
            }
            .frame(maxWidth:.infinity)
            .frame(height:100)
            .background(.blue)
            
            VStack{
                Text("お問合わせ内容を入力してください。").padding()
                Group{
                    TextField("お名前",text:$CFVM.name)
                        .keyboardType(.default)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .frame(maxWidth: .infinity)
                        
                    Text(CFVM.namePrompt)
                        .multilineTextAlignment(.leading)
                        .frame(maxWidth:.infinity,alignment: .leading)
                        .padding(.leading, 10.0)
                        .foregroundColor(.red)
                        .font(.caption2)
                    
                }.padding(.bottom, 10.0)
                
                Group{
                    TextField("email",text:$CFVM.email)
                        .keyboardType(.emailAddress)
                        .autocapitalization(.none)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .frame(maxWidth: .infinity)
                      
                    Text(CFVM.emailPrompt)
                        .multilineTextAlignment(.leading)
                        .frame(maxWidth:.infinity,alignment: .leading)
                        .padding(.leading, 10.0)
                        .foregroundColor(.red)
                        .font(.caption2)
                }.padding(.bottom, 10.0)
                
                Group{
                    TextField("問合わせ内容",text:$CFVM.contactBody)
                        .keyboardType(.emailAddress)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .frame(maxWidth: .infinity)
                      
                    Text(CFVM.contactBodyPrompt)
                        .multilineTextAlignment(.leading)
                        .frame(maxWidth:.infinity,alignment: .leading)
                        .padding(.leading, 10.0)
                        .foregroundColor(.red)
                        .font(.caption2)
                }.padding(.bottom, 10.0)
                
                Button(action:{
                    let url = URL(string:"https://script.google.com/macros/s/AKfycbzZ_QO36OHfVPV1OgltU52jyBVyEdfHYHkdVBqB-xnUnU30E_rmhod18zjpVh-KJWoO/exec")!

                    var request = URLRequest(url: url)

                    request.httpMethod="POST"
                    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
                    request.httpBody="name=\(CFVM.name)&&email=\(CFVM.email)&&body=\(CFVM.contactBody)".data(using:.utf8)

                    let task = URLSession.shared.dataTask(with: request) { data, response, error in

                        if let error = error {
                            print("クライアントエラー: \(error.localizedDescription) \n")
                                    return
                        }
                        guard let data = data, let response = response as? HTTPURLResponse else {
                          print("データがありませんでした。")
                          return
                        }

                        
                        if response.statusCode == 200 {
                            do{
                                let result = try JSONSerialization.jsonObject(with: data) as! Dictionary<String,Any>
                                self.message = "\(result["message"] as! String)"
                                
                            }catch{
                                print("ERROR")
                            }
                            
                        }
                       
                    }
                    task.resume()
                }){
                    Text("送信")
                        .frame(minWidth: 160)
                        .foregroundColor(.white)
                        .padding(12)
                        .background(Color.accentColor)
                        .cornerRadius(8)
                }
                .opacity(CFVM.isComplete ? 1 : 0.5)
                .disabled(!CFVM.isComplete)

                Spacer()
                    
            }.frame(maxWidth:.infinity).frame(height:500)
                            
        }
    }
}

struct ContactFormView_Previews: PreviewProvider {
    static var previews: some View {
        ContactFormView()
    }
}
```

# 関連コンテンツ
* 前：[iOSで簡易コーポレートサイト（アプリ）を作成する #2 -バリデーション編-](https://qiita.com/minimumskills/private/aed53f9d185592aecdda)
* [超シンプルなWeb（アプリ）作成を通して各種フロントエンド技術を体験する - 2023 Early -](https://qiita.com/minimumskills/private/9e7efe86e244bb9844b0)