Edited at

iOS/Swiftで画像を送信し、GAE/GoからGCSに画像を保存する


はじめに

GCSに画像を保存するのに結構ハマったので、簡単なサンプルでまとめる。1

「iOS/Swift+APIKit」と「GAE/Go+gin」のサンプルですが、ライブラリ等は適宜読み換えてください。


GAE/Go


前提

Google Cloud Storageのセットアップを済ませていること。


実装

エラーハンドリングは省略しています


gae.go

import (

"net/http"
"github.com/gin-gonic/gin"
)

func init() {
router := gin.Default()
http.Handle("/",getRouter())
}

func getRouter() *gin.Engine {
router := gin.Default()
router.GET("/upload/images", UploadImage)
return router
}



uploadImage.go

import (

"io/ioutil"

"cloud.google.com/go/storage"
"github.com/gin-gonic/gin"
"google.golang.org/appengine"
"google.golang.org/appengine/file"
)

func UploadImage(c *gin.Context) {
// 送られてきた画像データを取得する
fileHeader, err := c.FormFile("testImage")
imageFile, err := fileHeader.Open()

// appenigineのContextを取得
ctx := appengine.NewContext(c.Request)

// Storage上のbucket名を取得
bucket, err := file.DefaultBucketName(ctx)

// Storageを扱うclientを取得
client, err := storage.NewClient(ctx)

// Writerの生成
savePath := "hogehoge.png" //「icons/hoge.png」とか書ける
writer := client.Bucket(bucket).Object(savePath).NewWriter(ctx)
writer.ContentType = "image/png"

// []byteとして画像を取得
byteContainer, err := ioutil.ReadAll(imageFile) // ioutil.ReadXXXは重いので要注意

// 書き込み、保存する
_, err := wc.Write(byteContainer)
err = wc.Close()
}



画像のURL

画像ファイルのURLは、こんな感じで取れる

func GetUserImageURL(ctx context.Context, pathInBucket string) string {

const cloudStorageHOST = "https://storage.googleapis.com/"
projectID := appengine.AppID(ctx)
const projectDomain = ".appspot.com"
return cloudStorageHOST + projectID + projectDomain + "/" + pathInBucket
}


クライアント(iOS)

適当な画像をローカルのGAEにPOSTする。

nilチェックは省略しています。


main.swift

func uploadImage() {

let url = URL(string: "https://is1-ssl.mzstatic.com/image/thumb/Purple115/v4/f7/c4/0d/f7c40d38-759f-ae55-571a-3790b2d3aca5/source/0x0ss-85.png")!
let data = NSData(contentsOf: url)!
let request = SaveImageRequest(ImageData: data as Data)
Session.send(request) { result in print(result) }
}


SaveImageRequest.swift

// APIKit+Codableの構成

import APIKit

struct SaveImageResponse: Codable { //省略。受け取るレスポンスがあれば定義する }

struct SaveImageRequest: APIKit.Request {
typealias Response = SaveImageResponse

var ImageData: Data

let baseURL: URL = URL(string: "http://localhost:8080")!
var path: String {return "/upload/images"}
let method: APIKit.HTTPMethod = .post

var bodyParameters: BodyParameters? {
return MultipartFormDataBodyParameters(
parts: [MultipartFormDataBodyParameters.Part(
data: ImageData,
name: "testImage",
mimeType: "image/png",
fileName: "testImage.png")])
}
}



実行!

0) gcloud auth logingcloud auth application-default loginを叩き、認証を完了させる

1) バケットを指定してサーバーを起動

dev_appserver.py <app.yamlのpath> --default_gcs_bucket_name <バケット名>

2) iOSからリクエストを送信 (あるいはcurl等)

3) GCSをブラウザあるいはgsutilコマンドで確認し、画像が保存されているのを確かめる


参考





  1. ちなみに、Google Blobstoreは非推奨となってる。