標準とAlamofireでAPIコール処理を書き比べてみる(Swift)

## はじめに

先日、初めてAlamofireを使ってAPIのコール処理を実装しました。
せっかくなので、標準の `URLSession.dataTask` メソッドを使った場合と書き比べてみます。

## 環境

- Swift：5.0.1
- Alamofire：4.8.2

## 例

以下のAPIからディズニーランドの住所を取得し、構造体に格納します。
http://zipcloud.ibsnet.co.jp/api/search?zipcode=2790031

```json:レスポンス
{
	"message": null,
	"results": [
		{
			"address1": "千葉県",
			"address2": "浦安市",
			"address3": "舞浜",
			"kana1": "ﾁﾊﾞｹﾝ",
			"kana2": "ｳﾗﾔｽｼ",
			"kana3": "ﾏｲﾊﾏ",
			"prefcode": "12",
			"zipcode": "2790031"
		}
	],
	"status": 200
}
```

## 実装を比べてみる

### 共通処理

構造体は `Decodable` を使って実装しました。
レスポンスの一部のみ抜粋しています。

```swift:Address.swift
struct Address: Decodable {
    var results: [Result]

    struct Result: Decodable {
        var address1: String
        var address2: String
        var address3: String
        var kana1: String
        var kana2: String
        var kana3: String
    }
}
```

住所の取得は `getAddress` メソッドを呼び出すことにします。

```swift:住所の取得
getAddress(zipCode: "2790031")
```

### 標準

標準の `URLSession.dataTask` メソッドを使った実装です。

```swift:
import Foundation

// ...

    private var address: Address?

    private func getAddress(zipCode: String) {
        let baseUrlString = "http://zipcloud.ibsnet.co.jp"
        let searchPath = "/api/search"
        let searchUrl = URL(string: baseUrlString + searchPath)!
        guard var components = URLComponents(url: searchUrl, resolvingAgainstBaseURL: searchUrl.baseURL != nil) else {
            return
        }
        components.queryItems = [
            .init(name: "zipcode", value: zipCode),
        ] + (components.queryItems ?? [])
        var request = URLRequest(url: components.url!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: \(error)")
                return
            }
            guard let data = data else {
                return
            }

            do {
                self.address = try JSONDecoder().decode(Address.self, from: data)
            } catch let error {
                print("Error: \(error)")
            }
            }.resume()
    }
```


### Alamofire

続いて、Alamofireを使った実装です。

```swift:
import Alamofire

// ...

    private var address: Address?

    private func getAddress(zipCode: String) {
        let baseUrlString = "http://zipcloud.ibsnet.co.jp"
        let searchPath = "/api/search"
        let parameters: [String: Any] = ["zipcode": zipCode]
        let headers: HTTPHeaders = ["Content-Type": "application/json"]

        Alamofire.request(baseUrlString + searchPath, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: headers).responseJSON { response in
            guard let data = response.data else {
                return
            }

            do {
                self.address = try JSONDecoder().decode(Address.self, from: data)
            } catch let error {
                print("Error: \(error)")
            }
        }
    }
```

## おわりに

標準と比べてAlamofireの方がAPIコール処理を簡潔に実装できました。
ただ、標準をそのまま使うことはあまりなく、自前でラップすればもう少し簡潔に書くことができます。

もっといい実装やおすすめのラップ方法があれば、ご教授いただけると嬉しいです。