swiftで画像とテキストをmultipart同時送信

# まえがき
iOS開発で少し手こずったので備忘録として，載せておきます．
幾分冗長だなとか多々あると思いますが，長い目でよろしくお願いします．:star2:

# やりたいこと
iOS開発で画像とテキストを`multipart`で自社サーバへ同時送信

# 使用ライブラリ
Alamofire

# 仕様
## 概要
今回はチャットのようなアプリをイメージしてください．
送信は以下の4通りに分かれます．

| 画像  | テキスト |備考|
|:--:|:--:|:--:|
|◯|◯|画像とテキスト同時送信|
|◯|×|画像のみ送信|
|×|◯|テキストのみ送信|
|×|×|何も入力されていない|

今回の実装プログラムでは，上3つに対応しております．
一番下は必ずエラー処理として，PopUpみたいなのを出すといいと思われます．
今回は実装してないです．:frowning2:

## WebAPIの仕様
画像とテキストを投稿するにあたってサーバへPOSTリクエストを行います．
ここで，POSTリクエストの際に以下のようなbodyが要求されています．

| パラメタ | 型 |備考|
|:--:|:--:|:--:|
|user_id| int |誰が送ったのかが必要なので必須|
|message| string |投稿本文|
|img_file| string |画像|

# 送信実装
## cocoaPodsでAlamofireのインストール
本セクションではライブラリのインストール方法を記述します．

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

target 'chatApp' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for ChatApp
  pod 'Alamofire', '~> 4.2.0'

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

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

## 送信
本セクションでは実際にコードを使って`multipart`送信を行います．
postEntry関数を呼び出すと投稿が実行されます．
画像は写真で撮影およびギャラリーからの参照で取得できると思いますが，それは頑張ってください．:v:
画像は`Data型`です！
これは注意です．

```UIViewController.swift
import Alamofire
...

    // 投稿を送信するAPIの実装
    // 第一引数: ユーザID int 型
    // 第二引数: 投稿本文 string 型
    // 第三引数: 投稿画像 Data? 型 
    // 第四引数: 投稿画像の拡張子: String? 型
    func postEntry(userId: Int, body: String?, image: Data?, imageExtension: String?) {
        
        Alamofire.upload(multipartFormData: { (multipartFormData) in
            if image == nil && body == nil { // どっちも何も入っていない時returnで終了
               return
            }

            // multipartFormDataというオブジェクトにappendすると送信するデータを追加していきます
            // まず，idを追加
            multipartFormData.append("\(userId)".data(using: .utf8)!,
                                                 withName: "user_id",
                                                 mimeType: "text/plain")
            // 次，画像を追加
            // 画像を送らない時は image が nil となっている
            if image != nil {
                multipartFormData.append(image!, withName: "img_file",
                                                 fileName: "img_file." + self.mImageExtension!,
                                                 mimeType: "image/" + imageExtension!)
            }
            // 最後に投稿するテキスト本文を追加
            // 投稿がnilの時は本文に何も入っていない
            if body != nil {
                multipartFormData.append(body.data(using: .utf8)!,
                                              withName: "body",
                                              mimeType: "text/plain")
            }
   
        }, to: "https://自社サーバのドメイン/ディレクトリhoge/ディレクトリfuga") { (encodingResult) in
            switch encodingResult {
            case .success(let upload, _, _): // 成功
                upload.responseJSON { response in
                    if !response.result.isSuccess {
                        print("# ERROR")
                    } else {
                        // TODO: ここに成功した時に任意の処理をかく
                    }
                }
            case .failure(let error): // 失敗
                print(error)
            }
        }
    }

...

```

# 終わりに
ちょっと改造してテストはしてないですが，こちらで多分通ると思います．
質問や改善要求などどしどしためらいもなく，うぇるかむです．
読んでいただきありがとうございました．

Androidの場合 -> https://qiita.com/hisakioomae/items/9588e41ead50bd62f186