【3分で実装完了!】Swiftの通信ライブラリMoyaの使い方を現役iOSエンジニアがコード付きで教えます!

Moyaの使い方TOP

こんにちは!Apple信者のiOSエンジニアです。

この記事では、iOSアプリの通信をよりスマートに実現するためのライブラリ・Moyaについて使い方を解説しています。

忙しい方や初学者の方向けに、すぐに動かせるよう2022年版の実際のソースコードを載せてご紹介

この記事をお読みいただくことで、3分もあれば簡易的にAPIを動かせるでしょう。

Moya自体は有名なライブラリですから、解説してくださっている素晴らしい記事はもうすでにたくさんありますよね。

ただ内容によっては応用的すぎて、初学者の方やすぐに動かしたいと思う方には「それで結局どうすればいいの?」と思う部分もあるかもしれません。

そこで、今回は試しに「DeepL」という翻訳サービスが公開しているAPIを、GETで叩いている実際のコードをご紹介。

またソース内のそれぞれの処理について、どのような役割を持っているのかも説明していきますね。

この記事が役に立ちそうな人

Swift初心者の人でライブラリを実装したい人
・急ぎでSwiftを使ってAPI通信を実装したい人

この記事でわかること

・Moyaの基本的な使い方
・Moyaで翻訳APIを叩く方法
・Moyaを使うためのセットアップ

スポンサーリンク

Moyaとは

Moyaとは、Swiftで通信を行う際のライブラリのこと。

Alamofireという便利な通信ライブラリをラッピングしていて、使い慣れればSwift標準のURLSessionを使うより簡潔に快適にAPI通信を行うことが可能です。

実行した環境

僕の手元の環境は、Xcode13.2.1とmacOS Monterey(バージョン12.1)です。

Xcodeバージョン
macOSバージョン

以前のバージョンのXcodeで書いたコードから変えていませんが問題なく動くので、手元の環境にはそこまで神経質にならなくて大丈夫でしょう。

スポンサーリンク

Moyaを使うための準備

ここからは、Moyaを使うためのセットアップを行っていきます。

Moyaをインストール出来ている人は、読み飛ばしてもらって構いません

CocoaPodsの導入

今回のチュートリアルでは、CocoaPodsを使ってMoyaをプロジェクトに追加していきます。

CocoaPodsがない人は、まずCocoaPodsの導入からですね。

ターミナルからsudo gem install cocoapodsを実行しましょう。

sudo gem install cocoapods

できたら続けてターミナルからpod setupを実行すれば、CocoaPodsの導入は完了です。

pod setup
スポンサーリンク

Podfileの作成

CocoaPodsと同様に、まだPodlfieを用意していない人はここで用意してきます。

ターミナルでプロジェクトフォルダまで移動して、pod initコマンドでPodfileを作成しましょう。

pod init

CocoaPodsを使ってライブラリをインストール

CocoaPodsの導入が完了したら、Podfileの編集です。

プロジェクトフォルダ内にあるPodfileを開いてください。開くアプリはテキストエディタなど何でも大丈夫ですよ。

またこのPodfileはRubyの記法に基づいて書かれています。Rubyについては完全に理解していなくても、このPodfileは使えますので大丈夫ですよ。

できたら、以下のコードを参考にしてあなたの手元にあるPodfileも編集してみてください。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'DigitalAppleFarmSample' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for DigitalAppleFarmSample

# ここを書き足そう
pod 'Moya'

  target 'DigitalAppleFarmSampleTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'DigitalAppleFarmSampleUITests' do
    # Pods for testing
  end

end

書き足す必要があるのは、pod ‘Moya’の1行ですね。

ここまで出来たら、ターミナルでプロジェクトのディレクトリにいるまま、以下のようにpod installコマンドを実行してMoyaをインストールしてください。

pod install

無事インストールができたら、プロジェクトファイルにworkspace(.workspace拡張子のプロジェクト)が作成されるはず。

新規作成したworkspace

Moyaを使うこのチュートリアルでは、もともとあるプロジェクトではなくこのworkspaceを開いてコードを記述していく形になります。

Moyaの使い方

では実際にworkspaceを開き、Moyaを使うためのコードを記述していきましょう。

Moyaの設定ファイルを用意、記述

まず、Moyaのマネジャーファイルとなるものを作成していきましょう。

ファイル名は僕の環境では仮に「MoyaManager」としました。

できたら以下のようにコードを書き込んでいきましょう

import Foundation
import Moya

// Enum型(列挙体)で定義
enum DeepLApi {
    // 向き先を無料APIに(こっちの向き先は今回使いません)
    case deepL(text: String, source_lang: String, target_lang: String)
    // 向き先を有料APIに(今回使うのはこちら)
    case deepLPro(text: String, source_lang: String, target_lang: String)
}

// 拡張しTargetTypeに準拠
extension DeepLApi: TargetType {
    
    // その①
    var baseURL: URL {
        switch self {
        case .deepL:
            return URL(string: "https://api-free.deepl.com")!
        case .deepLPro:
            return URL(string: "https://api.deepl.com")!
        }
    }

    // その②
    var path: String {
        return "/v2/translate"
    }

    // その③
    var method: Moya.Method {
        return .get
    }
    
    var sampleData: Data {
        return Data()
    }
    
    var task: Task {
        switch self {
        case .deepL(let text, let source_lang, let target_lang):
            return .requestParameters(parameters: ["auth_key": "個別トークン", "text": text, "source_lang": source_lang, "target_lang": target_lang], encoding: URLEncoding.default)
            
        case .deepLPro(let text, let source_lang, let target_lang):
            return .requestParameters(parameters: ["auth_key": "個別トークン", "text": text, "source_lang": source_lang, "target_lang": target_lang], encoding: URLEncoding.default)
        }
    }
    
    // その④
    var headers: [String : String]? {
        return nil
    }
    
}


前述の通り、今回はDeepLという翻訳APIを叩くことを例にしてご紹介しています。

単純に「こちらから投げたワードを言語指定で翻訳する」というケースは、上のようにクライアントの作成を行えばOKです。

それぞれの処理の役割

では、上に定義したDeepLApiクラスについて簡単に説明していきましょう。

まずはDeepLApiという名前で、Moya通信のオブジェクトをEmun型(列挙体)にて定義しています。

こうして列挙体で定義しておけば、叩きたいURLが増えたときにこのEmun型に追加していくだけという実装が可能になります。

通信の向き先を切り替えるのも簡単ですね。

できたらextensionで拡張を行い、ここに行いたい通信設定を記述していきます。

細かい処理に関しては、コメントで振った番号と以下を照らし合わせてください。

  • その①:URLの向き先の定義(今回の例ではDeepL APIのURLをセット)
  • その②:APIのパスをセット
  • その③:HTTPメソッド(今回はGET)を設定
  • その④:リクエストヘッダの設定

その③のHTTPメソッドに関しても、分岐処理をかけてあげればGETだけでなくPOSTやPUTなど、状況に応じたAPI通信が可能になりますよ。

その④のリクエストヘッダは今回は不要なので設定していませんが、デバイストークンやPushトークンなどをヘッダに詰める必要がある場合にはこちらに記述しましょう

僕が今回叩いているAPIは諸事情あって有料版ですが、DeepLは無償でAPIの公開も行っています。もし全く同じ環境でぱぱっと試したい人は、DeepL APIにアカウント登録して無料版を使ってみると良いでしょう。

なので実際に使う場合には、baseURLの部分とリクエストパラメータはあなたの環境に合わせて書き換えていただければと思います。

通信を行いたい場所で呼び出す

上のMoyaManagerファイルの記述が問題なく済んだら、あとは通信を行いたい箇所で呼び出すだけです。

今回はアプリのView描画直後に通信を走らせられるように、イニシャルとなるViewControllerのviewDidLoad関数内で呼び出しを行ってみますね。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
     // プロバイダのセットアップ
        let provider = MoyaProvider<DeepLApi>()
        provider.request(.deepLPro(text: "Clapton is God", source_lang: "EN", target_lang: "JA")) { result in
            
            // 処理後の挙動の指定
            switch result {
                // 成功時
            case .success(let response):
                /* 成功時の処理を記述 */
                
                // 失敗時
            case .failure(let error):
                /* 失敗時の処理を記述 */
                print(error.localizedDescription)
            }   
        }
    }
}

これだけです。今回はDeepL APIを使って、英語の文字列「Clapton is God」を日本語に変換するリクエストを行っています。

シンプルですね!

あとは成功したcaseの中で、print関数などで確認するなりパースするなりと、よしなに使ってくださればと思います。

単に確認を行うのならば、ソースコードのようにdump関数やprint関数を使って中身を展開する。

あるいは僕の場合には、下記のようにJSONDecoderを使ってJSONからモデルクラスにマッピングを行っています。

// 成功時
case .success(let response):
   let data = response.data
   let deepLModel = try? JSONDecoder().decode(DeepLModel.self, from: data)
  print(deepLModel?.translations.first?.text ?? "")

print関数で出力も行ってみましたので、コンソールの値を見てみましょう。

Moyaの通信結果

これだけの少ない行数の記述にも関わらず、正しく日本語に翻訳されたテキストを受け取れていることがわかりますね。

またもしJSONデータのパース方法についてご検討中の方に関しては、こちら「【Swift】UnboxからCodableへのお引越し方法解説!JSONパーサは純正のCodableがおすすめな理由」で詳しく書いておりますので読んでみてください。

検証!MoyaとSwift標準の通信記法比較

Moyaのメリットは、かなりシンプルな記述でAPI通信が実装できてしまうこと。

ではSwiftの標準記法と比べて、どれほどMoyaが簡略化できているのかを検証していきましょう。

先程実装したものと同じことを、ライブラリを使わずにSwiftで書いてみたものが以下になります。

        // URL、パラメータのDict、パラメータの文字列変数を用意
        var urlStr = "https://api.deepl.com/v2/translate"
        let parameter =  ["auth_key": "d2c840c0-2af4-6987-fe32-6ae95f833d24", "text": "Clapton is God", "source_lang": "EN", "target_lang": "JA"]
        var parameterStr = ""
        
        // パラメータの値をエンコーディングしながら結合して文字列に
        for key in parameter.keys {
            let encodeValue = parameter[key]!.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
            parameterStr += "&" + key + "=" + encodeValue!
        }
        // URL文字列とパラメータ文字列を結合
        urlStr += "?" + parameterStr
        
        // URL文字列をURLへと変換
        guard let url = URL(string: urlStr) else { return }
        
     // タスクの用意
        let request = URLRequest(url: url)
        let session = URLSession.shared
        let task = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
            
            let deepLModel = try? JSONDecoder().decode(DeepLModel.self, from: data!)
            
        }
        // タスクの実行
        task.resume()

上は僕がふと思いついて思うがままにSwiftで書いたものですが、Swift標準で何も考えずに書くと、

  • パラメータ文字列の作成
  • パラメータの値のURLエンコーディング
  • リクエストやセッションのセットアップ
  • タスクの開始呼び出し

など、プログラマ側でやらなければいけない作業が増えることがわかります。

なおかつ上に僕が書いたように何も考えずにSwiftの標準で通信処理を書くと、URLごとに同じ処理を繰り返さなければいけません。場合ごとにパラメータをセットし直すというのも面倒ですよね。

僕の実際の体験談として、後先を考えずに通信処理を記述してすごく困ったことが何回かあります。

本来ならば使い回せる処理なのに、何度も同じように書かなければいけない。

iOSに限らずエンジニアとって、これはいちばんNGなパターンの一つですよね。

関数などにまとめてしまうことでもう少しシンプルになるとは思いますが、怠け者の僕としては、省ける手間はできるだけ省いておきたいもの。

Moyaを使えば、以下のようにスムーズです。

        let provider = MoyaProvider<DeepLApi>()
        provider.request(.deepLPro(text: "Moya is Hero", source_lang: "EN", target_lang: "JA")) { result in
            
            // 処理後の挙動の指定
            switch result {
                // 成功時
            case .success(let response):
                
                // 失敗時
            case .failure(let error):
                print(error.localizedDescription)
            }
            
        }

今回の例で言えばMoyaManagerクライアントクラスを作成しておく手間さえありますが、FatViewControllerを防止するためにも、呼び出したい場所ではたったこれだけのコードで通信を行えますよ。

Moyaがエラーなどでうまく使えないときのチェックポイント

ここまでやってみて、万が一Moyaを使った通信がうまくいかないときには、今一度お手元をチェックしてみてください。

単純なミスが原因だった場合は、すぐに解決することもあります。

import文が記述されているか確認

ファイルの頭にimport Moyaが記述されているか確認しましょう。

これがなければ、Moya関連のクラスや関数を使うことは出来ません。

叩きたいAPIのSSL化を確認

ATSが有効になっている場合、SSL化されているURL(httpsから始まるもの)しか扱えません。

AppleはSSL化を推奨していますが、テスト的にSSL化されていないURLを叩く際の救済措置もあります。

もしもテストなどでSSL化されていないURLを叩く場合には、以下のようにInfo.plistからATSを無効化しましょう。

ATS設定その①

まずはInfo.plistにATS設定プロパティを追加します。

できたら、Allow Arbitrary Loadsのプロパティを追加。

ここを「YES」に設定することで、httpから始まるURL(SSL化されていないURL)へのアクセスも許容できます。

ただこれはあくまでも救済措置であり、セキュリティ面を考えても、アプリのリリースまでにはSSL化されたAPIを用意するようにしましょう。

workspaceを開いて作業しているか確認

もとからあるプロジェクトを開いても、そこにはMoyaのライブラリは含まれていません。

そのためプロジェクトではなく、workspaceを開いて作業できているか今一度確認をしてみましょう。

ちゃんとworkspaceを開いているかの確認

さいごに

この記事では、さくっとMoyaを使ってAPI通信を行う方法のチュートリアルを行ってきました。

iOS開発に慣れている人はともかくとしても、開発を始めたばかりの人からすると、ネット上の情報は参考にしづらい部分もあると思います。

当然ですが全編英語(もしくは日本語でも機械翻訳調)の情報が多かったり、Moyaとプラスアルファの玄人向けの情報ばかり拾ってしまったり。

この記事ではシンプルにMoyaの使い方を解説しておりますので、初学者の方で「ひとまず取っ掛かりがほしい」と考えている場合や、お忙しい方で「大至急APIの実行結果を確認したい」という場合などにお役立ていただければ幸いです。

お付き合いをありがとうございました!

スポンサーリンク
Moyaの使い方TOP
Twitterもやってます!