Golang で画像ファイルをAWS S3にアップロードをするサンプルコード

環境

  • CentOS7
  • go1.x
  • glide0.x

インストール

$ dep ensure -add github.com/aws/aws-sdk-go

ファイル構成

  • path/to/go/src/psychedelicnekopunch/go-sample/
infrastructure/
  ├ AwsS3.go
  └ Config.go
images/
  └ sample.png
main.go

サンプルコード

infrastructure/Config.go

package infrastructure

type Config struct {
	Aws struct {
		S3 struct {
			Region string
			Bucket string
			AccessKeyID string
			SecretAccessKey string
		}
	}
}

func NewConfig() *Config {

	c := new(Config)
	
	// ex) アジアパシフィック (東京): ap-northeast-1
	c.Aws.S3.Region = "ap-northeast-1"
	c.Aws.S3.Bucket = "YOUR Bucket Name"
	c.Aws.S3.AccessKeyID = "YOUR AWS Access key ID"
	c.Aws.S3.SecretAccessKey = "YOUR AWS Secret Access Key"

	return c
}

infrastructure/AwsS3.go

package infrastructure


import (
	"errors"
	"fmt"
	"mime/multipart"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)


type AwsS3 struct {
	Config *Config
	Keys AwsS3URLs
	Uploader *s3manager.Uploader
}


type AwsS3URLs struct {
	Test string
}

func NewAwsS3() *AwsS3 {

	config := NewConfig()

	// The session the S3 Uploader will use
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			// Access key ID と Secret Access Key は IAM から作成する。
			// 一度作成した Access key ID の Secret Access Key は csv ファイルでダウンロードしていない場合は、
			// 確認する手段がないので新しくアクセスキーを作成する必要がある。
			Credentials: credentials.NewStaticCredentialsFromCreds(credentials.Value{
				AccessKeyID: config.Aws.S3.AccessKeyID,
				SecretAccessKey: config.Aws.S3.SecretAccessKey,
			}),
			Region: aws.String(config.Aws.S3.Region),
		},
	}))

	return &AwsS3{
		Config: config,
		Keys: AwsS3URLs{
			Test: "test/images",
		},
		// Create an uploader with the session and default options
		Uploader: s3manager.NewUploader(sess),
	}
}


func (a *AwsS3) UploadTest(file multipart.File, fileName string, extension string) (url string, err error) {

	if fileName == "" {
		return "", errors.New("fileName is required")
	}

	var contentType string

	switch extension {
	case "jpg":
		contentType = "image/jpeg"
	case "jpeg":
		contentType = "image/jpeg"
	case "gif":
		contentType = "image/gif"
	case "png":
		contentType = "image/png"
	default:
		return "", errors.New("this extension is invalid")
	}

	// Upload the file to S3.
	result, err := a.Uploader.Upload(&s3manager.UploadInput{
		// ACL の設定は重要
		ACL: aws.String("public-read"),
		Body: file,
		Bucket: aws.String(a.Config.Aws.S3.Bucket),
		// content-type の設定も忘れずに
		ContentType: aws.String(contentType),
		Key: aws.String(a.Keys.Test + "/" + fileName + "." + extension),
	})

	if err != nil {
		return "", fmt.Errorf("failed to upload file, %v", err)
	}

	return result.Location, nil
}

使いかた

main.go

  • path/to/go/src/psychedelicnekopunch/go-sample/images/sample.png を s3 に test.png というファイル名でアップロードする。
package main

import (
	"fmt"
	"os"

	"psychedelicnekopunch/go-sample/infrastructure"
)


func main() {

	var (
		file *os.File
		err error
		awsS3 *infrastructure.AwsS3
		url string
	)

	// このファイルと同じ階層に images/sample.png がある想定
	file, err = os.Open("images/sample.png")

	if err != nil {
		fmt.Printf(err.Error())
		return
	}
	defer file.Close()

	awsS3 = infrastructure.NewAwsS3()

	// multipart.File と os.File は同じように扱える
	url, err = awsS3.UploadTest(file, "test", "png")

	if err != nil {
		fmt.Print(err.Error())
		return
	}
	fmt.Print(url)
}

go 製フレームワーク gin を用いた使いかた

main.go


package main

import (
	"github.com/gin-gonic/gin"

	"psychedelicnekopunch/go-sample/infrastructure"
)

func main() {

	g := gin.Default()

	g.POST("/uploads", func (c *gin.Context) {
		awsS3 := infrastructure.NewAwsS3()

		// func (c *gin.Context) FormFile(name string) (*multipart.FileHeader, error)
		fileHeader, err := context.FormFile("uploadImage")
		if err != nil {
			c.JSON(400, gin.H{ "message": err.Error() })
		}

		// func (fh *FileHeader) Open() (multipart.File, error)
		file, err := fileHeader.Open()
		if err != nil {
			c.JSON(400, gin.H{ "message": err.Error() })
		}

		url, err = awsS3.UploadTest(file, "test", "png")
		if err != nil {
			c.JSON(400, gin.H{ "message": err.Error() })
		}

		c.JSON(201, gin.H{ "message": "success" })
	})

	g.Run(":8080")
}