【GO】base64形式で受け取った画像をGCSにアップロードする

# はじめに
画像をGCSアップロードする際、画像をフロント側から
1. **「multipart/form-data」**で受けとる記事は多くはあったのですが、
2. **「Base64(json)」**で受け取るものが見当たらなかったので、こちらを実装してみました。:relieved:

### 本記事のゴール
「**GO**を使って、フロント側から**base64**で受け取った画像をGCSにアップロードすること」

### 動作環境
go 1.17

# 目次

- [準備](#準備)
- [ソースコード](#ソースコード)
- [解説](#解説)
- [補足](#補足)
- [参考サイト](#参考サイト)

# 準備
### jsonKeyの取得
取得した~~~.jsonをルート直下に配置します。(どこでも良いです)

```markdown
main.go
gstorage.go
~~~.json
```

細かい取得手順は割愛します。自分は以下記事を参考にさせていただきました:slight_smile:
[Google Cloud Storageの接続設定](https://docs.trocco.io/s/article/Google-Cloud-Storage%E3%81%AE%E6%8E%A5%E7%B6%9A%E8%A8%AD%E5%AE%9A?language=ja)

### 用語確認
1. `bucket` : storageのバケット名
2. `object` : **アップロード後**のファイル名

objectはアップロード後のファイル名であることに注意してください。

### sdkインストール
以下コマンドでインストールできます。
`go get -u cloud.google.com/go/storage`
	
# ソースコード
```go:gstorage.go
func UploadFile(bucket string, object string, imgBase64 string) error {

	credentialFilePath := "./~~~.json"
	ctx := context.Background()
    
	client, err := storage.NewClient(ctx, option.WithCredentialsFile(credentialFilePath))
	if err != nil {
		return fmt.Errorf("storage.NewClient: %v", err)
	}
	defer client.Close()

	decodedImage, err := base64.StdEncoding.DecodeString(imgBase64)
	if err != nil {
		return fmt.Errorf("DecodeString: %v", err)
	}

	decodedReader := bytes.NewReader(decodedImage)
	wc := client.Bucket(bucket).Object(object).NewWriter(ctx)

	if _, err = io.Copy(wc, decodedReader); err != nil {
		fmt.Errorf("io.Copy:%v", err)
	}
	if err := wc.Close(); err != nil {
		fmt.Errorf("wc.Close:%v", err)
	}

	fmt.Printf("Blob %v uploaded \n", object)


	return nil
}
```
# 解説
### client生成
はじめにcredentialFileのpathを指定して、
ctxという名前のコンテキストやclientを生成します。

```go:gstorage.go
	credentialFilePath := "./~~~.json"
	ctx := context.Background()
    
	client, err := storage.NewClient(ctx, option.WithCredentialsFile(credentialFilePath))
	if err != nil {
		return fmt.Errorf("storage.NewClient: %v", err)
	}
```

### [ ]byteに変換
次にフロント側から受け取ったbase64をdecodeして、[ ]byte型にします。

```go:gstorage.go
	decodedImage, err := base64.StdEncoding.DecodeString(imgBase64)
	if err != nil {
		return fmt.Errorf("DecodeString: %v", err)
	}
```

>ちなみに`StdEncoding`と`RawStdEncoding`の違いは、
base64文字列に「=」（padding）を含むか含まないか、みたいです
参考）　[技術向上](https://tech-up.hatenablog.com/entry/2019/01/06/175112)

あとは公式通りにやればできました。
[【google公式】オブジェクトのアップロード](https://cloud.google.com/storage/docs/uploading-objects?hl=ja#storage-upload-object-go)
# 補足
### multipart/form-data

ちなみに`multipart/form-data`形式で送る際は、
>ファイルを送信する場合、requestsのヘッダーに「multipart/form-data」を設定する必要があるため、JSONをJSONとして送れない

参考）[【Python】RequestsでJSONデータと画像ファイルのPOST送信と取得](https://max999blog.com/python-how-to-post-json-and-file-same-time/)

みたいです。こちらの記事にあるようにjsonっぽく受け取る方法もあるみたいです。

本記事を通して間違っているところがございましたらご指摘いただければと思います！:bow:

# 参考サイト
本記事作成にあたって他に以下のサイトを参考にさせていただきました
[【google公式】オブジェクトのアップロード](https://cloud.google.com/storage/docs/uploading-objects?hl=ja#storage-upload-object-go)

[GAE/GOからmultipart/form-dataでGCSに画像をアップロードする](https://sanshiro.dev/article/5705808872472576)

[いろいろ備忘録日記](https://devlights.hatenablog.com/entry/2021/07/25/070000)

[Go言語(golang)でGoogle Cloud Storageへファイルをアップロードする](https://dev.classmethod.jp/articles/golang-write-gcs/)

[GolangでGoogle Cloud Storageに画像やファイルをアップロードする（os.Setenvで環境変数GOOGLE APPLICATION CREDENTIALSを設定する）](https://www.irohabook.com/go-upload-google-cloud-storage)