Go の echo ってWebサーバーでサクッと REST しちゃう

  • 104
    いいね
  • 1
    コメント

Go言語勉強しながらWebサーバー立てたいなーどうしようかなーって思ってたときに
きっと色々候補はあるんだけど

labstack/echo

Echo is a fast :rocket: and unfancy micro web framework for Go.

っての見つけた。
Go言語そのものの勉強以外は最小限に抑えたいし、
RESTでjson返すだけならこれで十分かなって思った。
速いらしいし。

Echo の使い方

公式ドキュメントに大概載ってる。

インストール

go get github.com/labstack/echo
go get github.com/dgrijalva/jwt-go

一発でOK。

動かす

main.go
package main

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
    "./handler"
)

func main() {
    // Echoのインスタンス作る
    e := echo.New()

    // 全てのリクエストで差し込みたいミドルウェア(ログとか)はここ
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    // ルーティング
    e.GET("/hello", handler.MainPage())

    // サーバー起動
    e.Start(":1323")    //ポート番号指定してね
}
handler/handler.go
package handler

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

func MainPage() echo.HandlerFunc {
    return func(c echo.Context) error {     //c をいじって Request, Responseを色々する 
        return c.String(http.StatusOK, "Hello World")
    }
}
go run main.go

http://localhost:1323/hello にアクセスします。

多分ファイル分けたくなるだろうから最初から分けておいた。
他のフレームワークとあんまり変わらないかな。簡単。

ルーティングで e.GET() って書いてるけど、
もちろん e.POST() とか e.PUT() とか書けばメソッドで分けれますよ。

ただ、他のフレームワークと違ってルーティングの文字列は前方一致のみみたい。
正規表現は多分使えないんじゃないかな。

Path parameter を使う

(2016/3/15 追記項目)
RESTと言えば Path parameter だよね。
リソースの場所を表さなきゃなんだから当然やね。

main.go
e.Get("/hello/:username", handle.MainPage())    //セミコロンの所がプレースホルダになる

って感じでセミコロン使ってプレースホルダを宣言しといて、

ハンドラの方で

handle.go

func MainPage() echo.HandlerFunc {
    return func(c echo.Context) error {
        username := c.Param("username")    //プレースホルダusernameの値取り出し
        return c.String(http.StatusOK, "Hello World " + username)
    }
}

ってやるだけやね。

ちなみに c.Param("username") の所を c.P(0) みたいにインデックスで指定も出来るっぽい。
でもどうせプレースホルダ宣言するし、どういうときにインデックス使うかちょっとわかんない。

後クエリパラメータ(/hoge/?key=value みたいな、?付きのパラメータ)とか
フォームのデータとか送れるみたいだけど、
そっちもほとんど使い方一緒だから公式ドキュメントの該当ページ見てね。

Basic認証

認証はBasic認証のみ対応済み。
これも簡単。

main に

main.go
e.Use(interceptor.BasicAuth())

みたいなのを追加したら、
interceptor パッケージを作って、その中に

auth.go
package interceptor

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

func BasicAuth() echo.MiddlewareFunc {
    return middleware.BasicAuth(func(username, password string) bool {
        return username == "validUser" && password == "validPassword"
    })
}

usernamepassword の部分に Basic認証の情報が入ってくるので、
その値が正しいかどうかを判別します。

ココで true を返せば本来のリクエストされたハンドラへ処理がうつり、
false を返せば、401が返される。

個別のページで認証の有無を変えたい場合は?

さっきの方法では全ページにミドルウェアを挟んでしまうので、
認証が必要でないページを作りたいときに困ってしまう。

あるリクエストだけに特定のミドルウェアを挟みたいときは

e.Get() のところで

main.go
e.Get("/user/apps/:username", handle.MainPage(), interceptor.BasicAuth())

という感じで、ハンドラの後ろに足してあげるとOK。

公式ドキュメントでは「グループ機能制御出来るよ!」
って書いてあったけど良く分かんなかった。

また解決したら書き足すかも。

json の書き出し

json の出力も

handle.go

jsonMap := map[string]string{
            "foo": "bar",
            "hoge": "fuga",
        }

        return c.JSON(http.StatusOK, jsonMap)

みたいな感じで、c.Stringc.JSON にしてマップなりなんなり渡すだけ。
余裕やね。

CORS

json 出力できたら次はやっぱり CORS じゃんね。

main.go

e.Use(standard.WrapMiddleware(cors.New(cors.Options{
        AllowedOrigins: []string{"http://example.com"},
    }).Handler))

ミドルウェアとしてこれをはさむだけで OK っぽい。

echo を使ってみて。

他にもファイルアップロードとか websocket も使えるみたいだし、
簡単なデータのやりとりは一通りできる。

あと印象に残ってるのは、コードをちょっと読んでたら router の所に

// NOTE: Slow zone...

ってコメントが入ってた。
スピードを上げることを意識してコーディングしてるんだなーって思った。
Go自体速いし、大した影響はないと思うんだけどね。

2017/04/30 編集

shinriyo@github さんにインストール方法など、記事を書いた当時と変わっていた部分を
編集していただきました。