Edited at

Go製のフレームワークechoを使ってJSONを返すWebサーバーを作り、GoogleAppEngineで動かす

More than 3 years have passed since last update.

UPDATE 2016/06/12

2.0がリリースされました。

v2.0.1でやってみたところこの記事内容は動くようですが、少しだけ変更点があるようです。

https://echo.labstack.com/guide/migrating

また、ローカルでバージョンアップするには以下のようにします。

# テストのフレームワークがないよと怒られるので事前に取得します。

go get github.com/stretchr/testify
# echoのアップデート
go get -u github.com/labstack/echo/...


GoでJSONを返すAPIサーバを作ってみたかったので調べました。


echoとは

Goで作られている軽量なフレームワークで、他のものに比べて現在も開発が活発です。最新版はv1.4ですが、v2.0.0betaが出ているので近々バーションアップされるようです。


Echo is a fast and unfancy HTTP server framework for Go (Golang). Up to 10x faster than the rest. https://labstack.com/echo

https://github.com/labstack/echo



Installation

チュートリアルに従ってやってみます。

# echoのインストール

go get github.com/labstack/echo/...
# プロジェクトのディレクトリを作ります
cd $GOPATH/src
mkdir echo-sample
cd echo-sample

app.goというファイルを作ります。


app.go

package main

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

func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Run(standard.New(":1323"))
}


で、実行。

go run app.go

# 何も表示がなくわかりづらいですが、http://localhost:1323 に'Hello, world'と表示されます


GoogleAppEngineで動かす

ローカル環境で動かすのは簡単なのですが、GAEで動かすのにルーティングがうまくいかず悩んでいたら普通に解説がありました(--#)


https://labstack.com/echo/recipes/google-app-engine


これに沿って行きます。


JSONを返すAPIと静的なファイル配信


app.go

package main

// 起点となるファイルです
var e = createMux()


app-standalone.go

// +build !appengine,!appenginevm

package main

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"))
}


publicを静的ファイルの場所としたので、HTMLでも作っておきます


public/index.html

<h1>HELLO, ECHO!</h1>


Userの情報をJSONで返します


users.go

package main

import (
"net/http"

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

// UserのJSONの形を指定します。
type (
user struct {
ID string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
)

var (
users map[string]user
)

func init() {
// 初期データを登録してみます
users = map[string]user{
"1": user{
ID: "1",
Name: "ジョナサン・ジョースター",
Age: 20,
},
"2": user{
ID: "2",
Name: "ディオ・ブランドー",
Age: 21,
},
}

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

g.POST("", createUser)
g.GET("", getUsers)
g.GET("/:id", getUser)
}

// Userの作成、一覧、詳細です
func createUser(c echo.Context) error {
u := new(user)
if err := c.Bind(u); err != nil {
return err
}
users[u.ID] = *u
return c.JSON(http.StatusCreated, u)
}

func getUsers(c echo.Context) error {
return c.JSON(http.StatusOK, users)
}

func getUser(c echo.Context) error {
return c.JSON(http.StatusOK, users[c.P(0)])
}



GoogleAppEngine用のルーティング

AppEngine用には設定はあまりしなくて良いようです。


app-engine.go

// +build appengine

package main

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()も書かなくて良い


設定ファイルも追加します


app.yaml

runtime: go

api_version: go1

handlers:
- url: /
mime_type: text/html
static_files: public/index.html
upload: public/index.html

- url: /favicon.ico
mime_type: image/x-icon
static_files: public/favicon.ico
upload: public/favicon.ico

- url: /scripts
mime_type: text/javascript
static_dir: public/scripts

- url: /.*
script: _go_app



GoogleAppEngineにデプロイ

SDKのインストールは割愛します。ダウンロードはこちらから

https://cloud.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go

SDKを使ってローカルで起動してみましょう。

ファイル構成はこんな感じです。

.

├── app-engine.go
├── app-standalone.go
├── app.go
├── app.yaml
├── public
│   └── index.html
└── users.go

goapp serve

# can't find import: "github.com/rs/cors" と言われたのでインストールします
go get github.com/rs/cors

# retry
goapp serve
> INFO 2016-04-24 07:25:34,339 admin_server.py:116] Starting admin server at: http://localhost:8000

# 無事に起動したようなので、http://localhost:8080 にアクセスすると <h1>HELLO, ECHO!</h1> と表示されます
# JSONを取得してみます
curl -s http://localhost:8080/users/1 | jq
{
"id": "1",
"name": "ジョナサン・ジョースター",
"age": 20
}

できているようですね。

Googleのクラウドコンソールからプロジェクトを作成し、プロジェクトIDを控えます

https://console.cloud.google.com/

そして、以下のコマンドを実行すると認証画面が出るので許可します。

cd $GOPATH/src

appcfg.py -A <YOUR_PROJECT_ID> -V v1 update echo-sample/
> 04:28 PM Deployment successful.

成功したので、http://YOUR_PROJECT_ID.appspot.com にアクセスして、HELLO,ECHO!と表示されていればOKです。

JSONのAPIも確認してみましょう。

curl -s <YOUR_PROJECT_ID>.appspot.com/users | jq

{
"1": {
"id": "1",
"name": "ジョナサン・ジョースター",
"age": 20
},
"2": {
"id": "2",
"name": "ディオ・ブランドー",
"age": 21
}
}


まとめ

軽量フレームワークechoを使ってJSONを返すAPIを作成し、GoogleAppEngineで動かしてみました。JSONを返すだけであれば、標準ライブラリのnet/httpでも問題ありませんが、echoは開発が活発で4000starほどついているので試してみました。近々2.0も出るようなので、また試してみたいと思います。