12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

API通信を行う際のエラー処理

Last updated at Posted at 2021-04-02

検索キーを用いてgithubAPIを叩き、リポジトリのデータを取得するメソッドの中でエラー処理を書いたのでメモとして記録します。
searchBarに入力した検索ワードからリポジトリを検索してTableViewに表示し、検索を押してエラーが出た際に内容をUIAlertControllerで表示するシンプルなアプリです。
こんな感じ↓

#環境
・macOS Big Sur バージョン11.2.3
・XCode 12.4
・Swift5.3.2
・Alamofire5.4.1 + Codableを使用

#1. エラーを定義する

APIError.swift
enum APIError: Error{
    case searchWordEmpty
    case invalidURL
    case networkError
    case unknown
    
    var title: String{
        switch self{
        case .networkError:
            return "ネットワークエラー"
        case .unknown:
            return "不明なエラー"
        default:
            return "検索エラー"
        }
    }
    
    var description: String{
        switch self{
        case .searchWordEmpty:
            return "検索ワードを入力してください。"
        case .invalidURL:
            return "別の検索ワードを試してください。検索ワードには半角英数字のみお使いいただけます。"
        case .networkError:
            return "接続環境の良いところでもう一度お試しください。"
        case .unknown:
            return "不明なエラーです。"
        }
    }

    func showAlert(from: UIViewController){
        UIAlertController.showAPIErrorAlert(error: self, from)
    }
}

ユーザーに分かりやすいように4種類のエラーに分けました。
ユーザー側で修正不可能なエラーは全て不明なエラーとして表示されます。
#2. UIAlertControllerの拡張機能を作る

ExtensionUIAlertController.swift
extension UIAlertController{
    static func showAPIErrorAlert(error: APIError, _ viewController: UIViewController){
        let title = error.title
        let message = error.description
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let action = UIAlertAction(title: "OK", style: .default) { (action) in
            alert.dismiss(animated: true, completion: nil)
        }
        alert.addAction(action)
        viewController.present(alert, animated: true, completion: nil)
    }
}

titleに先程定義したエラーのタイトル、messageにエラーの詳細(description)を表示させ、OKを押したら閉じるアラートを作成し表示します。
拡張機能+staticでどこでも簡単に呼び出せるようにしました。
#3. API通信を行うメソッドでエラーを取得する

GithubAPI.swift
func getRepositoryDataOf(_ searchWord:String, completion:@escaping(Result<(),APIError>)->Void){

        guard let url = URL(string: "https://api.github.com/search/repositories?q=\(searchWord)")
        else { return completion(.failure(.invalidURL)) } //①

        AF.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON { (response) in
            do{
                guard let data = response.data
                else { throw APIError.networkError } //②
                let result = try JSONDecoder().decode(Repository.self, from: data)
                let tableViewDatasource = TableViewDataSource.shared
                tableViewDatasource.repositories = result
                DispatchQueue.main.async {
                    completion(.success(()))
                }
            }catch{
                if error as? APIError == APIError.networkError{
                    completion(.failure(.networkError)) //②
                }else{
                    completion(.failure(.unknown)) //③
                }
                print(error)
            }
        }
    }

Result型を用いてcompletionでエラーを渡します。
successの時のデータはシングルトンに格納しているため値渡しは行っていません。
①guard letを使ってエラーを返します
②guard letでthrowしたエラーをdo catch構文、completionを使い渡しています。
③上記2つ以外のAPI通信時に起こるエラーは全てunknownとして渡します
#4. ViewControllerでアラートを表示する

ViewController.swift
func getRepositoryData(searchWord: String){

        GithubAPI.getRepositoryDataOf(searchWord){ [unowned self] (result) in
            switch result{
            case .success(()):
                tableView.reloadData()
            case .failure(let error): 
                error.showAlert(from: self)
            }
        }
    }

//searchBarDelegateメソッド
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

        guard let searchWord = searchBar.text,
              !searchWord.isEmpty
        //検索ワードが空の時のエラー
        else { return UIAlertController.showAPIErrorAlert(error: .searchWordEmpty, self) } 
        getRepositoryData(searchWord: searchWord)
    }

API通信を行ってcompletionで受け取ったエラーごとにalertを作成し表示しています。
検索ワードが空の時はAPI通信を行う前にguard letを用いてエラーを表示しています。

#5. 終わりに
API通信時のエラーはこれで網羅できたのではないでしょうか。
修正したほうが良い点があればコメントください!

12
8
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
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?