LoginSignup
5
7

More than 1 year has passed since last update.

【Swift】AlamofireでAPI通信をする

Posted at

はじめに

今回はQiitaAPIを叩いてAlamofireで通信していみたいと思います。

作るもの

ScreenShot 2021-05-11 3.31.43.png

GitHub

実装

モデル

struct Article: Codable {
    let title: String
    let user: User
}

struct User: Codable {
    let id: String
}

コントローラー

final class ArticleListViewController: UIViewController {

    @IBOutlet private weak var tableView: UITableView!
    private var articles = [Article]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        getArticles()

    }

}

private extension ArticleListViewController {

    func getArticles() {
        APIClient().request { result in
            switch result {
                case .success(let articles):
                    self.articles = articles
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                case .failure(let error):
                    self.showAPIAlert(error: error)
            }
        }
    }

    func showAPIAlert(error: APIError) {
        let alert = UIAlertController(title: error.title, message: nil, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "閉じる", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }

}

// MARK: - UITableViewDataSource
extension ArticleListViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return articles.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = articles[indexPath.row].title
        return cell
    }

}

API

import Alamofire

typealias ResultHandler<T> = (Result<T, APIError>) -> Void

struct APIClient {

    func request(handler: @escaping ResultHandler<[Article]>) {
        let urlString = "https://qiita.com/api/v2/items"
        let url = URL(string: urlString)
        guard let url = URL(string: urlString) else {
            handler(.failure(.invalidURL))
            return
        }
        AF.request(urlString)
            .responseJSON { response in
                guard let data = response.data else {
                    handler(.failure(.invalidResponse))
                    return
                }
                do {
                    let articles = try JSONDecoder().decode([Article].self, from: data)
                    handler(.success(articles))
                } catch {
                    handler(.failure(.unknown(error)))
                }
            }
    }

}

その他

enum APIError: Error {
    case invalidURL
    case invalidResponse
    case unknown(Error)
}

extension APIError {

    var title: String {
        switch self {
            case .invalidResponse: return "無効なレスポンスです。"
            case .invalidURL: return "無効なURLです。"
            case .unknown(let error): return "予期せぬエラーが発生しました。\(error)"
        }
    }

}

解説

大切なところのみ解説します。
本来はurlをそのまま書いておいたりするのは良くないのですが、今回はAamofireの解説ということで、省略します。

ここでリクエストを送信しています。

AF.request(urlString)

以下のようにして、通信を行います。

APIClient().request { result in
    switch result {
        case .success(let articles):
            self.articles = articles
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        case .failure(let error):
            self.showAPIAlert(error: error)
    }
}

URLSessionとの比較

let request = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        handler(.failure(.unknown(error)))
        return
    }
    if let data = data {
        do {
            let articles = try JSONDecoder().decode([Article].self, from: data)
            handler(.success(articles))
        } catch {
            handler(.failure(.unknown(error)))
        }
    }
}
task.resume()

Alamofireの方が明らかに簡潔にかけていますね。

おわりに

終わりです。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7