Closed3

golang の echo を試す。

nonanonnononanonno

https://echo.labstack.com/

直近使わなさそうなものは省略。

セットアップ

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 といった形でアクセスできる。

nonanonnononanonno

ミドルウェア

https://echo.labstack.com/docs/category/middleware

色々な機能を追加できるらしい? 認証とかロガーとかプロキシとか。以下は、

  1. ミドルウェアとしてロガーとリカバーを追加する
  2. /adamin エントリーポイントを Group 関数で作り、その下を Basic 認証で保護するミドルウェアを設定する。
  3. /admin の内容を、 Group 関数が返すオブジェクト経由で設定する
  4. それはそれとして /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"))
}
nonanonnononanonno

テンプレート

https://echo.labstack.com/docs/templates

Context#Render(code int, name string, data interface{}) errordataを用いてテンプレートのレンダリングを行い、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にクローズされました