[Swift] Swift製WebフレームワークVaporを使用してファイルアップロード API を作成する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんばんは。モバイルアプリサービス部の平屋です。

以下の記事でNode.js + express + Multerでファイルアップロード API を作成する手順を紹介しました。

[Node.js] express + Multer を使用してファイルアップロード API を作成する

同じ機能を持つアプリを、Swift製WebフレームワークVaporを使用して作成してみましたので、その手順を紹介していきます。

検証環境

  • macOS Sierra 10.12.3
  • Xcode 8.2.1
  • Homebrew 1.1.1
  • swiftenv 1.2.1
  • Swift Snapshot DEVELOPMENT-SNAPSHOT-2017-03-09-a
  • Vapor Toolbox 1.0.5

環境構築

以下の記事と同じ手順でswiftenvVapor Toolboxを使用して環境を構築しました。

Vaporで始めるサーバーサイドSwift 〜Mac上での環境構築からHello, World!まで〜 (swiftenv, Vapor Toolboxを使用)

環境が構築できたら、vaporコマンドを使用してサーバーサイドアプリのプロジェクトを作成します。

$ vapor new vapor-multipart-formdata-sample

main.swiftを修正

プロジェクトのSources/Appディレクトリ内のmain.swiftを修正して、POSTリクエストを受け付けられるようにします。

以下のように、13-26行目を追加します。

import Vapor
import Foundation

let drop = Droplet()

drop.get { req in
    return try drop.view.make("welcome", [
        "message": drop.localization[req.lang, "welcome", "title"]
    ])
}

// ここから
drop.post { req in
    guard let field = req.formData?["file"] else {
        return JSON(["result":"receive failure"])
    }

    do {
        let dest = URL(fileURLWithPath: field.filename!)
        try Data(field.part.body).write(to: dest)
    } catch {
        return JSON(["result":"save failure"])
    }

    return JSON(["result":"success"])
}
// ここまでを追加

drop.resource("posts", PostController())

drop.run()

14行目では、RequestオブジェクトのformDataプロパティからname"file"Field構造体を取り出しています。Field構造体は、ファイル名やバイナリデータなどを持ちます。

19行目ではファイル名を取り出し、20行目では受け取ったデータをファイルとして保存しています。

動作確認

サーバーサイドアプリを実行

以下のコマンドを実行して、サーバーサイドアプリのビルドとサーバーの起動を行います。ポート8080でリクエストを受け付けるようになります。

$ vapor build
$ vapor run serve

iOS アプリからファイルをアップロードする

iOS アプリの場合、以下のような実装でファイルをアップロードできます。

iOS + Swift + Alamofire

func upload() {
    let path = Bundle.main.path(forResource: "image", ofType: "png")
    let fileURL = URL.init(fileURLWithPath: path!)

    Alamofire.upload(
        multipartFormData: { multipartFormData in
            multipartFormData.append(fileURL, withName: "file")
    },
        to: "http://192.168.0.11:8080/",
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .success(let upload, _, _):
                upload.responseJSON { response in
                    debugPrint(response)
                }
            case .failure(let encodingError):
                print(encodingError)
            }
    }
    )
}

iOS + Objective-C + AFNetworking

- (void)upload
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];
    NSURL *fileURL = [NSURL fileURLWithPath:path];
 
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:@"http://192.168.0.11:8080" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileURL:fileURL
                                   name:@"file"
                                  error:nil];
    } progress:nil success:^(NSURLSessionTask *task, id responseObject) {
        NSLog(@"success");
    } failure:^(NSURLSessionTask *task, NSError *error) {
        NSLog(@"error:%@", error.localizedDescription);
    }];
}

動作結果

iOS アプリからアップロード操作を行い、サーバーサイドアプリのルートディレクトリにファイルがアップロードされることを確認できました。

vapor-swift-file-upload-1

さいごに

本記事ではSwift製WebフレームワークVaporを使用してファイルアップロード API を作成する手順を紹介しました。

以前作成したNode.js版のものと同じぐらい簡単に作れることがわかりました。

今回解説したサンプルアプリケーションは以下のリポジトリで公開しています。

参考資料