万年素人からHackerへの道

万年素人がHackerになれるまで殴り書きするぜ。

ginでGroup化したルーティング

いままでこんな書き方してたが冗長。

func (controller *ShopsController) Setup() {
        controller.Router.POST("/shops", controller.createShop)
        controller.Router.GET("/shops", controller.listShops)
        controller.Router.GET("/shops/:shop_id", controller.getShop)
        controller.Router.PUT("/shops/:shop_id", controller.updateShop)
        controller.Router.DELETE("/shops/:shop_id", controller.deleteShop)
}

Martiniはこうかける GitHub - go-martini/martini: Classy web framework for Go

Ginにもあった。 GitHub - gin-gonic/gin: Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Grouping routes

func main() {
    router := gin.Default()

    // Simple group: v1
    v1 := router.Group("/v1")
    {
        v1.POST("/login", loginEndpoint)
        v1.POST("/submit", submitEndpoint)
        v1.POST("/read", readEndpoint)
    }

    // Simple group: v2
    v2 := router.Group("/v2")
    {
        v2.POST("/login", loginEndpoint)
        v2.POST("/submit", submitEndpoint)
        v2.POST("/read", readEndpoint)
    }

    router.Run(":8080")
}

私の例は、https://github.com/dcu/gin-scaffoldを使ってるので、

以下のようになる。 controller.Routerを変数v1に置き換えたような感じに。

func (controller *ShopsController) Setup() {

        v1 := controller.Router.Group("/shops")
        {
                v1.POST("", controller.createShop)
                v1.GET("", controller.listShops)
                v1.GET("/:shop_id", controller.getShop)
                v1.PUT("/:shop_id", controller.updateShop)
                v1.DELETE("/:shop_id", controller.deleteShop)
        }
}

気をつけるのは、v1.GET("", controller.listShops)これ。 /を入れてv1.GET("/", controller.listShops)としてしまうと、 http://localhost:4000/shopsでなくhttp://localhost:4001/shops/のように最後に/が必要だし 色々なページのURLが変わってしまう。

ginのformでDELETEやPUTのメソッドを送る方法

ginのフレームワークでできるか?

HTMLのformmethodPUTとか書いてもおそらくブラウザが対応してない?せいか GET扱いになる。 おそらく、知らないmethodを書くとGETになる仕様なのかも?

portaltan.hatenablog.com

これをみるとhiddenに書けばいけるっぽい。 Sinatraが対応してくれてる?

ここ見る限りモダンなRailsなども対応 html - Why don't the modern browsers support PUT and DELETE form methods? - Stack Overflow

しかしginは・・・。できなかった・・。

探すとginのgithubのフォーラム上で

PUT does not work. Always 404 · Issue #450 · gin-gonic/gin · GitHub

ん?<form action="/1" method="post"> これは? しかし、これは単にidのことですね。関係ない。

go get github.com/martini-contrib/method

インポートする。

import(
        "ghoulme/controllers"
        "github.com/gin-gonic/gin"
        "net/http"
        "os"
        "github.com/martini-contrib/method"
)

これ追加。

var overrideHandler = method.Override()
func Override(c *gin.Context) {
        overrideHandler.ServeHTTP(c.Writer, c.Request)
}
        router := gin.Default()
        router.Use(Override) // これ追加。
        router.LoadHTMLGlob("templates/**/*")
        controllers.Setup(router

これで一応putできるようになった。

が・・・・つねに404となる。 誰か教えて。 またはわかったらまた記事書きます。

golang template テンプレートの優先順

テンプレートの優先順。

ginのテンプレートの機能で以下のようにテンプレートを読む設定する。

router := gin.Default()
router.LoadHTMLGlob("templates/*/*.tmpl")

こうすればtemplates/なんとか の[なんとか]が自由になる。

templates/shop/index.tmpl templates/aho/index.tmpl

の2つ同じファイル名、ただし親フォルダが違う。

呼ぶ側はこんな感じ。c*gin.Contextだ。

        c.HTML(http.StatusOK, "index.tmpl", gin.H{
                "title": "shop",
                "body": shopsResponse,
        })

これでやると、templates/shop/index.tmplの方が呼ばれた。 おそらくアルファベット順でshopとahoだとaよりもsの方が後だが、 s開始のshopが呼ばれたのは、後からロードされたのが上書きしたから?

試しに、sよりもtの方が後なのでtemplates/tra/index.tmplとテキトーに作った。 そうすると、templates/shop/index.tmplではなく、templates/tra/index.tmplが優先されてた。

しかし、明示的に同じファイルがある時の指定方法はどうやるのかしら?