【Poteto】GolangでWebフレームワークはじめ③ Routingを良い感じにする
はじめに
Golang
のwebAPIフレームワークをせっせと作っているものです。大分開発も進んできて、もう使えるレベルになってきました!!今は自分が書いてたgolangのwebAPIプロジェクトをPotetoに移行しながら改良を進めています。
簡単なサンプルAPIも公開しているので、興味ある方はぜひ使ってみてください。
この記事は第三回ということで今までのものは以下から
さて、今回のテーマは、「Routingを良い感じにする」です。
Routingを良い感じにする
良い感じのRouterとは何なのか?それを確かめるため、人々はアマゾンの奥地へと向かった。。。というのは置いといて、自分の感覚で良いルーターを考えました。
今までのPotetoのRouting
今までのPotetoのRoutingはよくあるフレームワークって感じです。
func main() {
p := poteto.New()
p.GET("/exmaple", exmapleHandler)
p.Run(":8080")
}
これが悪いという話ではなく、インパクトは薄いんですよね。世の中メンテナンスの行き届いたWebフレームワークがあふれてる中で、個人開発を選択する理由はないので、インパクトが欲しいところです。
Potetoの課題:middlewareTree
middlewareTreeについてはぜひ前回の記事をご覧ください。
PotetoはmiddlewareTreeとRoutingがダイレクトに紐づかないという課題を抱えていました。
func main() {
p := poteto.New()
exmapleApi := p.Combine("/example", <your middleware>)
p.GET("/exmaple", exmapleHandler)
p.Run(":8080")
}
これは設計をシンプルにするためのものであり、個人的には気に入りつつも、やっぱり脳内で、どのミドルウェアが適用されるのか考えにくいという課題がありました。
RailsのRouting
そしてもうひとつ昔触って鮮明に覚えていた快適なRoutingがありました。それがRailsのroutingです。(記憶があやふやなので、全然違うことを言っているかもしれません。)
resources :photos do
get "view"
post "create"
end
これめちゃくちゃ分かりやすいですよね。一目で/photos/view
や/photos/create
にマッピングされているのが分かります。もはやこれ羅列よりわかりやすいんですよね。
get "/photos/view"
post "/photos/create"
良い感じのRoutingとは:僕の感覚
上記を振り返って「良い感じのRouting」を以下のように定義しました。
Namespaceで区切られており、middlewareのマッピングがはっきり分かる
それではそういった良い感じのRoutingを実際に作ってみました。
Poteto.Leaf: 良い感じのRouting
これが現在のPotetoのRoutingです(もちろん上記のやつも動きます)。
どうですか?良い感じじゃないですか?少なくとも自分は満足したのでOKです。
func main() {
p := poteto.New()
p.Leaf("/users", func(userApi poteto.Leaf) {
userApi.Register(<your middleware>)
userApi.GET("/", controller.UserHandler)
userApi.GET("/:name", controller.UserNameHandler)
})
p.Run("8080")
}
Poteto.Leaf()
の実装
実装は単純で、Leaf
という構造体に*poteto
とbasePath
を持たせています。
Poteto.Leaf(basePath, leafHandler)
ではまずLeaf
構造体を作ります
type Leaf struct {
poteto Poteto
basePath string
}
func(p *poteto) Leaf(basePath string, handelr LeafHandler) {
leaf := NewLeaf(basePath, handler)
handler(leaf)
}
Leaf
ではそれぞれPoteto
の関数をbasePath
をプラスした状態でインターナルに呼ぶだけです。比較すると分かりやすいですね。
/* 従来のRouting */
userApi := p.Combine("/users", <your middleware>)
p.GET("/users", controller.UserHandler)
/* Leaf */
p.Leaf("/users", func(userApi poteto.Leaf) {
// Internal call p.Combine("/users", <your middleware>)
userApi.Register(<your middleware>)
// Internal call p.GET("/users", controller.UserHandler)
userApi.GET("/", controller.UserHandler)
})
実装上の工夫としては以下の2点でした。
- PotetoとLeafの相互参照を避ける
- Leafの機能を最低限に絞り、参照が行われても理解しやすいようにする
結構満足いく設計にもなりました。
さいごに
ここまで読んでいただき、ありがとうございます。今回は個人的に満足感の高い機能を入れることができました。ぜひ、良い感じになったPotetoのRoutingをお試しください
Discussion