swiftでwebAPIを呼び出してjsonデータを表示させる

# 概要

　この記事は初心者の自分がRESTfulなAPIとswiftでiPhone向けのクーポン配信サービスを開発した手順を順番に記事にしています。技術要素を1つずつ調べながら実装したため、とても遠回りな実装となっています。

　前回の[JSON形式でレスポンスをするwebAPIを作成する](https://qiita.com/Ajyarimochi/items/492dccaff21cba567e43)で（モックアップのレベルですが）リクエストパラメータで指定した番号のクーポン情報を`json`形式でレスポンスするクーポン配信APIができたので、リクエストする側のアプリをSwiftで実装します。

今回は

1. アプリからwebAPIにリクエストを投げる
2. レスポンスされた情報をjson形式でコンソールに表示する

の流れを一旦完成させ、アプリ画面にクーポンを表示する下準備をしようと思います。

### 参考

* [【swift】XcodeでiOSアプリのhttp通信を許可する方法](https://fukatsu.tech/permit-http-ios)
* [swiftでapiを叩いてJSONを取得してパースして画面に表示する方法](https://fukatsu.tech/api-tableview)


### 環境
Mac OS 10.15
Swift5
Xcode11.1

### アプリの仕様

* アプリ起動時にAPIにリクエストし、レスポンスされたクーポン情報をjson形式でコンソールに表示する。
* webAPIにリクエストする際、リクエストパラメータとしてクーポンコードを指定する。

# 手順

* Xcodeでクライアントアプリ側のプロジェクトを作成
* http通信を許可する設定をする
* webAPIとの通信部分をswiftで実装
* webAPIから受け取った情報を画面に表示する処理を実装
* 動作確認


### Xcodeでクライアントアプリ側のプロジェクトを作成

現在、SwiftUIがリリースされていますが、今回は多少経験のある従来のstoryboadを使います。

Xcodeを開いて、「Create a new Xcode project」を選択。
<img width="350" alt="open-xcode-mark.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/8710cd4e-6bb6-40a5-d5ea-cab5ed4e1c8e.png">


次の画面で、iOS の　Single View App を選択。
<img width="500" alt="select-project-type-mark.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/c8e0210c-5130-61d8-1bc2-7be6409cbf75.png">



次の画面でプロジェクトのオプションを設定。
この時、User Interface: は SwiftUI ではなく Storyboardを選択します。Product Name: や Team: Organization Name: などはご自身の設定を入れてください。

<img width="500" alt="choose-options-of-project-mask.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/0ae7fee7-c680-b719-b917-ca9f863a27f5.png">



### http通信を許可する設定をする

[参考にさせて頂いたサイト](https://fukatsu.tech/permit-http-ios)で紹介されている手順に従い、`Info.plist` ファイルを編集して http通信を許可します。


### webAPIとの通信部分をswiftで実装

とりあえず、swift側で 前回までに作成したクーポン配信APIを呼び出して、レスポンスを得られるところまで作成します。

swiftの`ViewController.swift`を下記の通り実装します。
Apiから取得する data、response、error の中身をコンソールに出力する事でswift側でapiのレスポンスを得られたか判断します。APIへのリクエストURLはコードにベタがきします。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // アプリがロードされた時に実行させたい処理を書きます

        let url: URL = URL(string: "http://127.0.0.1:8000/coupon/?coupon_code=0001")!
        let task: URLSessionTask = URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
            // コンソールに出力           
            print("data: \(String(describing: data))")
            print("response: \(String(describing: response))")
            print("error: \(String(describing: error))")
        })
        task.resume()        
    }
}
```

djangoのサーバを起動してクーポン配信APIを立ち上げたら、Xcodeでプログラムを実行してみます。iPhoneのシミュレータが起動しアプリの画面が開いたらXcodeのコンソール出力を確認します。画面には何も表示設定をしていないのでただの白い画面です。

Xcodeのコンソール出力を見るとdata、response、error の内容が出力されているので、レスポンスを得られていることを確認出来ました。
<img width="548" alt="swift-testrun-api-call-001-mask.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/1733af32-b70f-b0cf-41f0-16b08c2bb1e2.png">


django のサーバを起動したターミナルを確認すると、GETでリクエストを受けていることを確認できます。
<img width="503" alt="swift-testrun-api-response-001-mask.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/bd6c3af0-c17e-334a-c622-aa957a2e5ed0.png">



### レスポンスで受け取ったdataをswift側でJSONに変換する

APIとの疎通まで確認出来ましたので、次はレスポンスされたデータから情報を取り出すために、data型をJSONに変換する処理を追加します。

`URLSessionTask`のクロージャー部分にJSONに変換するためのコードを追加します。クロージャーに関する解説は参考にさせて頂いた記事をご覧ください。

`ViewController.swift`　の`URLSessionTask`の部分に、`print([json形式の変数])`を入れて、JSONに変換出来たか確認します。

```swift:ViewController.swift
       do{
                let couponData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)
                print(couponData) // Jsonの中身を表示
            }
            catch {
                print(error)
            }
```

djangoのサーバが起動中なのを確認してswiftを実行し、コンソール出力を見ます。コンソール出力にjsonの中身が表示されているので変換は成功です。

<img width="476" alt="swift-testrun-api-call-002.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/c5e91ea8-413a-c782-92e6-fc9a4be6daad.png">


jsonの中身は見れましたが、coupon_benefitsの部分が よく分からない文字列`（"1000\U5186\U5f15\U304d\U30af\U30fc\U30dd\U30f3\Uff01”）`になっています。
これを本来の文字列にするには、jsonのパースが必要です。


### jsonをパースする

data型をjsonに変換しただけだとANY型になっており、上記のようによく分からない文字列で表示されてしまいます。なので、ANY型をString型にキャストする必要があります。

`let couponData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)`

の後ろに、`as! [String: Any]` を付けます。

```
let couponData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: Any]
```

djangoのサーバが起動中なのを確認してアプリを実行し、コンソール出力を見るます。
`"coupon_benefits": 1000円引きクーポン！`になっているのでパース成功です。
<img width="484" alt="swift-testrun-api-call-003.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526594/d8586b58-c8a0-8c23-8181-c9cabc52dd02.png">



下記のコードは不要になったので削除します。

```
print("data: \(String(describing: data))")
print("response: \(String(describing: response))")
print("error: \(String(describing: error))")
```

以上でアプリの画面にapiで取得した情報を表示する準備が出来ました。