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というファイルを作ります。
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で動かすのにルーティングがうまくいかず悩んでいたら普通に解説がありました(--#)
これに沿って行きます。
JSONを返すAPIと静的なファイル配信
package main
// 起点となるファイルです
var e = createMux()
// +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でも作っておきます
<h1>HELLO, ECHO!</h1>
Userの情報をJSONで返します
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用には設定はあまりしなくて良いようです。
// +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()も書かなくて良い
設定ファイルも追加します
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も出るようなので、また試してみたいと思います。