takaya030の備忘録

PHP、Laravel、Docker などの話がメインです

GAE/Go + Echo でセッションを使う

Google App Engine for Go (GAE/Go) で動作している Echo の環境でセッションを使用する手順メモ

検証環境

Windows10 Home Edition
VirtualBox 5.1.22
Docker version 17.05.0-ce, build 89658be
docker-compose version 1.6.2, build 4d72027

GAE/Go, Echo 開発環境について

今回は下記サイトの手順で構築したものを使用します
takaya030.hatenablog.com

session パッケージについて

gorilla/sessions を GAE 対応させた下記パッケージを使用します
github.com

ディレクトリ構成

+---gaego
|   |   docker-compose.yml
|   |   
|   +---config
|   |   
|   +---data
|   |       Dockerfile
|   |   
|   +---glide
|   |       
|   +---sdk
|           Dockerfile
|            
+---logs
|    
+---www
    |       
    +---app
    |       app.yaml
    |       main.go
    |
    +---src
        |
        +---hello
                app.go
                app-engine.go
                app-standalone.go
                glide.yaml
                hello.go

各種ファイルの詳細

www/app/app.yaml

runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

www/app/main.go

package main

import (
	_ "hello"
)

func init() {
}

www/src/hello/app.go

package hello

var e = createMux()

www/src/hello/app-engine.go

// +build appengine

package hello

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/engine/standard"
    "net/http"
)

func createMux() *echo.Echo {
    e := echo.New()

    // note: we don't need to provide the middleware or static handlers, that's taken care of by the platform
    // app engine has it's own "main" wrapper - we just need to hook echo into the default handler
    s := standard.New("")
    s.SetHandler(e)
    http.Handle("/", s)

    return e
}

// main()は書かなくて良い

www/src/hello/app-standalone.go

// +build !appengine,!appenginevm

package hello

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/engine/standard"
    "github.com/labstack/echo/middleware"
)

// ログの設定や静的ファイルの場所指定などをしています
func createMux() *echo.Echo {
    e := echo.New()

    e.Use(middleware.Recover())
    e.Use(middleware.Logger())
    e.Use(middleware.Gzip())

    e.Use(middleware.Static("public"))

    return e
}

func main() {
    e.Run(standard.New(":8080"))
}

www/src/hello/glide.yaml

package: hello
import:
- package: github.com/labstack/echo
  version: v2.2.0
  subpackages:
  - engine/standard
  - middleware
- package: github.com/rs/cors
- package: github.com/gorilla/sessions
- package: github.com/gorilla/context
- package: github.com/dsoprea/goappenginesessioncascade
- package: github.com/dsoprea/go-logging

www/src/hello/hello.go

package hello

import (
    "net/http"
    "strconv"

    "github.com/labstack/echo"
    "github.com/labstack/echo/engine/standard"
    "github.com/rs/cors"

    "github.com/dsoprea/goappenginesessioncascade"
)

const (
    sessionName = "MainSession"
)

var (
    sessionSecret = []byte("SessionSecret")
    sessionStore = cascadestore.NewCascadeStore(cascadestore.DistributedBackends, sessionSecret)
)

func init() {

    g := e.Group("/hello")
    g.Use(standard.WrapMiddleware(cors.Default().Handler))

    g.GET("", getWorld)
}


// hello world

func getWorld(c echo.Context) error {

    w := c.Response().(*standard.Response).ResponseWriter
    r := c.Request().(*standard.Request).Request

    var foo int
    if sess, err := sessionStore.Get(r, sessionName); err != nil {
        panic(err)
    } else {

        if val, found := sess.Values["foo"]; found == false {
            foo = 0
        } else {
            foo = val.(int) + 1
        }

        sess.Values["foo"] = foo
        if err := sess.Save(r, w); err != nil {
            panic(err)
        }
    }

    return c.String(http.StatusOK, "Hello, World! foo is " + strconv.Itoa(foo))
}

glide によるパッケージインストール

$ cd gaego
$ docker-compose run --rm sdk /bin/bash -c "cd src/hello;glide up"

動作確認

以下のコマンドで開発用サーバーが起動します

$ docker-compose up -d

web ブラウザで http://192.168.99.100:8080/hello にアクセスして以下のような文字列が表示されれば成功です

Hello, World! foo is 0

"foo is" の数値はセッションに保存されていて、アクセスの度にインクリメントします
ブラウザをリロードすると数値がインクリメントするのが確認できます