Closed3
golang の echo を試す。
直近使わなさそうなものは省略。
セットアップ
go mod init <name>
go get github.com/labstack/echo/v4
Hello World
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
ルーティングとパラメータ
e.GET("/users" , ...)
のような形でルーティングができる。以下は/users/<id>
のように、パラメータの受け取りも含めた処理
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.GET("/users/:id", getUser)
e.Logger.Fatal(e.Start(":1323"))
}
// e.GET("/users/:id", getUser)
func getUser(c echo.Context) error {
// パラメータを取得する。`id` の箇所は、`:id` と一致している必要がある。
id := c.Param("id")
return c.String(http.StatusOK, id)
}
http://localhost:1323/users/foo でアクセスできる。 foo
が表示される。
クエリパラメータ
http://localhost:1323/show?team=foo&member=bar のように、?
の後に付けるあれ。
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.GET("/show", show)
e.Logger.Fatal(e.Start(":1323"))
}
func show(c echo.Context) error {
team := c.QueryParam("team")
member := c.QueryParam("member")
return c.String(http.StatusOK, "team: "+team+", member: "+member)
}
静的コンテンツ
e.Static("/static", "resource")
で、resource
以下のファイルを http://localhost:1323/static/hello.html といった形でアクセスできる。
ミドルウェア
色々な機能を追加できるらしい? 認証とかロガーとかプロキシとか。以下は、
- ミドルウェアとしてロガーとリカバーを追加する
-
/adamin
エントリーポイントをGroup
関数で作り、その下を Basic 認証で保護するミドルウェアを設定する。 -
/admin
の内容を、Group
関数が返すオブジェクト経由で設定する - それはそれとして
/users
は自由にアクセスできる
コード。
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
g := e.Group("/admin")
g.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == "joe" && password == "secret" {
return true, nil
}
return false, nil
}))
g.GET("", func(c echo.Context) error {
return c.String(http.StatusOK, "/admin")
})
track := func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
println("request to /users")
return next(c)
}
}
e.GET("/users", func(c echo.Context) error {
return c.String(http.StatusOK, "/users")
}, track)
e.Logger.Fatal(e.Start(":1323"))
}
テンプレート
Context#Render(code int, name string, data interface{}) error
は data
を用いてテンプレートのレンダリングを行い、text/html データとステータスコードを返す。テンプレートは Echo.Renderer
に設定することで使用できるようになる。テンプレートエンジンは任意のものを使用できる。
以下は Go の html/template
を使用した例。go初学者なので、go言語の文法に関するコメントも含む。
main.go
package main
import (
"html/template"
"io"
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
// echo.Renderer を実装する構造体
type Template struct {
// 紛らわしいが、この templates は echo.Renderer の文脈でのテンプレートとは関係ない。
// html/template パッケージのテンプレートを格納するためのフィールドで、Render メソッドを定義する時に内部的に使用される。
// 参考 https://www.twihike.dev/docs/golang-web/templates
templates *template.Template
}
// echo.Renderer は Render メソッドを持つインターフェース。
// 上記で定義した Template 構造体に対してこれを定義することで、echo.Renderer interface を実装したと言える。
// name はテンプレートの名前になるが、どのように使われるかは Render メソッドの実装に依存する。data も同様。
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
return t.templates.ExecuteTemplate(w, name, data)
}
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Template 構造体のインスタンスを生成する。
// parseGlob は引数に渡したパターンにマッチするファイルを全て読み込んでパースする。
// ここでは public/views ディレクトリ内の全ての .html ファイルを読み込む。(hello.htmlがある)
// テンプレートの名前は、ファイルの拡張子を除いた部分になり、内容はファイルの中身になる。
// いずれも html/template パッケージの文脈。
t := &Template{templates: template.Must(template.ParseGlob("public/views/*.html"))}
e.Renderer = t
e.GET("/hello", Hello)
e.Logger.Fatal(e.Start(":1323"))
}
func Hello(c echo.Context) error {
// 前述の Render メッソドの呼び出しになる。
return c.Render(http.StatusOK, "hello", "world")
}
mustache を使った例。
go get github.com/hoisie/mustache
main.go
package main
import (
"errors"
"io"
"net/http"
"github.com/hoisie/mustache"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
type MustacheTemplate struct{}
func (t *MustacheTemplate) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
// ここでは name は使わない。その場でテンプレートを作成する。
tmpl, err := mustache.ParseString("Hello mustache, {{c}}")
if err != nil {
return err
}
// 型アサーションで data を string に変換する。
str, ok := data.(string)
if !ok {
return errors.New("data is not string")
}
w.Write([]byte(tmpl.Render(map[string]string{"c": str})))
return nil
}
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Renderer = &MustacheTemplate{}
e.GET("/hello", Hello)
e.Logger.Fatal(e.Start(":1323"))
}
func Hello(c echo.Context) error {
return c.Render(http.StatusOK, "hello", "world")
}
このスクラップは2024/02/11にクローズされました