Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GoでRouter自作実装寄りな話
Search
bmf_san
June 23, 2021
Programming
250
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GoでRouter自作実装寄りな話
bmf_san
June 23, 2021
More Decks by bmf_san
See All by bmf_san
桃太郎で始めるRego入門‐今日から使えるRegoの基本編
bmf_san
0
64
完璧を求めない意思決定-アクセス制御基盤における制約との向き合い方
bmf_san
5
19k
AAPについて調べてみた
bmf_san
0
130
レーダーをつくる
bmf_san
0
79
契約テストとPactについて
bmf_san
0
120
5分でわかるSLO
bmf_san
2
170
権限について考える
bmf_san
2
160
自作HTTPルーターから新しいServeMuxへ
bmf_san
3
1.8k
古くなってしまったPHPフレームワークとPHPのバージョンアップ戦略
bmf_san
1
500
Other Decks in Programming
See All in Programming
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
780
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
760
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
240
スマートグラスで並列バイブコーディング
hyshu
0
140
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
260
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
680
The NotImplementedError Problem in Ruby
koic
1
790
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
330
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
190
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
500
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
350
net-httpのHTTP/2対応について
naruse
0
490
Featured
See All Featured
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
430
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
420
How STYLIGHT went responsive
nonsquared
100
6.2k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
160
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
390
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
140
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Thoughts on Productivity
jonyablonski
76
5.2k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.2k
Transcript
GoでRouter⾃作 実装寄りな話 @bmf_san 2021.06.23 社内LT
なんの話 • net/httpを拡張したrouterのライブラリ • net/httpの”⾜りないところ”を補う • /user/:idのような動的なルーティングができな い
ϒϩάͱ͔-5ͱ͔Ͱ͍·Θͨ͠ωλ
Github https://github.com/bmf-san/goblin
Goblin仕様 • net/http準拠 • 動的なルーティング • 名前付きのパラメータ(パスパラーメーター)をサポート/ users/:id • 正規表現も使える
/users/:id[^\d+$] • ミドルウェアをサポート • net/httpのhttp.Handlerインターフェースに従った関数をミドル ウェアとしてルーティングの処理に組み込める
Goblin例 IUUQTHJUIVCDPNCNGTBOHPCMJOCMPCNBTUFS@FYBNQMFTNBJOHPΛࢀর
有名どころ • ライブラリ • https://github.com/fasthttp/router • https://github.com/julienschmidt/httprouter • http://github.com/go-chi/chi •
FW • https://github.com/gin-gonic/gin • https://github.com/labstack/echo • https://github.com/gorilla/mux
Routerの役⽬ NJEEMFXBSFIBOEMFSͷखલͰॲཧ͞ΕΔΠϝʔδ
Routerの役⽬ • リクエストされたURLやHTTP Methodに応じて、 処理の実⾏を制御するアプリケーション • URLとアプリケーションの処理を結びつける
データ構造を考える ・Router≒⽂字列マッチング ・URLの階層構造と相性が良いデータ構造 →⽊構造
⽊構造
トライ⽊(プレフィックス⽊) ・⽂字列の集合を扱う⽊構造の⼀種 ・ざっくりいうと、⽂字列を探索しやすいように⽊に 格納したやつ ・ex. サジェスト、IPアドレス探索、形態素解析とか ⽂字列を扱う系のやつのベースだったりするぽい
もっと良い⽊ • 時間的計算量(処理時間)、空間的計算量(メモ リ)の効率を追求するなら他に選択肢がある • ex. Radix(Prefix) tree https://www.cs.usfca.edu/ ~galles/visualization/RadixTree.html
• 実装できなかった。ムズい。 • strings.Replacerは内部でRadix tree 実装してい る
トライ⽊を知る • https://www.cs.usfca.edu/~galles/visualization/ Trie.html • アルゴリズムのビジュアライズ • https://github.com/bmf-san/road-to-algorithm- master/tree/master/data_structures/tree/trie •
参照実装
オレオレトライ⽊
オレオレトライ⽊(旧) • 最初のリリースで実装していた⽊ • HTTPメソッドをノードに⼊れてしまうのはアンチパターンだった • ルーティングの処理にHTTPメソッドの⼀致を前提としてしまう • HandlerがHTTPメソッドに依存するような実装になってしまう •
middlewareの対応で不都合に • cf. https://bmf-tech.com/posts/⾃作ルーティングをアップデートした
主な構造体 NBQͱMJOLFEMJTUͷ߹ମͰΛදݱͨ͠Α͏ͳΠϝʔδʁ
Goでrouterを実装する上で知っておきたいこと • net/httpの概観 • どんな構造体があるか、どこを拡張したら良いか、どんなイン ターフェースに従うべきか • cf. https://golang.org/pkg/net/http/ •
HTTPサーバーの処理 • http.ListenAndServeから内部を⾒る • cf. https://bmf-tech.com/posts/GolangのHTTPサーバーのコード リーディング
HTTPサーバーのコードにdeep dive • 良く⾒るGoのHTTPサーバーのコード(⾊々省略さ れている)
HTTPサーバーのコードにdeep dive • 省略しないで書いたパターン
HTTPサーバーのコードにdeep dive • ServeHTTPは関数型のaliasであるHandlerFuncに置き換えることができる • cf. • func (f HandlerfFunc)
ServeHTTP(w ResponseWriter, r *Request) • https://golang.org/src/net/http/server.go?s=64180:64240#L2058
HTTPサーバーのコードにdeep dive • Mux(http.NewServeMux( ))は作らなくても良い。DefaultServeMuxを使うことができ る。 • DefaultServeMuxはServeMux型の構造体を持っており、HandlerFuncというmuxにルー ティングを登録する関数を実装している。 •
cf. • DefaultServeMux • https://golang.org/src/net/http/server.go?s=77627:77714#L2269 • func (mux *ServeMux) HandlerFunc(pattern string, handler func(ResponseWriter, *Request))
HTTPサーバーのコードにdeep dive • Server構造体(http.Server{})もわざわざ作らなくても良い。net/httpには ListenAndServe( )が⽤意されている。 • cf. • func
(*Server) ListenAndServe • https://golang.org/pkg/net/http/#ListenAndServe • func ListenAndServe(addr string, handler Handler) error
Routerを実装するには • →http.Handlerインターフェース を意識して、muxを作れば良い
ルーティングを登録する部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/router.go • メソッドチェーンでrouteを登録する処理 • ServeHTTPの実装(≒http.Handlerインターフェースの実装)した構造体を作る • ServeHTTP内では、ルーティング、ミドルウェア・ハンドラの実⾏を順番にやる
• 作った構造体はListenAndServeに渡される想定 • cf. https://github.com/bmf-san/goblin/blob/master/_examples/main.go
middleware対応のための実装 • cf. https://github.com/bmf-san/goblin/blob/master/ middleware.go • Sliceに保持したミドルウェアを順番に処理していく • 処理をラップしていくように実⾏する •
cf. https://github.com/bmf-san/goblin/blob/ master/_examples/main.go • いわゆるDecorator patternってやつだと思う
muxにあたる部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/trie.go • オレオレトライ⽊を頑張ってかく • 単純なトライ⽊を書いて、それを発展させていく • データ構造を考えきった時点で6~7割くらい完成ではある
• テストとデバッガを有効につかう • テストがないと前に進めないくらいテストを有⽤ • ⾊々なパターンのルート定義を考慮する必要があり、テストケースが結構悩ましい • デバッガは⽊の⽣成が上⼿くできているか確認したり、脳内デバッグで間に合わないときに有⽤ • 正規表現の利⽤ • 正規表現を使ったルーティングのケースに対応するためにregexpを使っている • strings.Replacerで代⽤できるならそっちが良い • Goでは正規表現はコストがかかる処理なのでキャッシュして再利⽤性を⾼めると良い • 後で対応しようと思っていたらPRもらえた • https://github.com/bmf-san/goblin/pull/17
ベンチマーク • ϕϯνϚʔΫςετ • cf. https://github.com/julienschmidt/go-http-routing-benchmark • go test -bench=“Goblin|Gin|GorillaMux|HttpRouter|Chi|Beego|Echo”
• ϕϯνϚʔΫ݁Ռ • cf. https://github.com/bmf-san/goblin/issues/ 34#issuecomment-864978325 • Routerબఆͷ؍ύϑΥʔϚϯε͚ͩͰͳ͘ɺػೳ໘net/ httpͷΠϯλʔϑΣʔεΛҙ͍ࣝͯ͠Δ͔Ͳ͏͔ͷόϥϯε͕େࣄ ͦ͏ • cf. https://github.com/julienschmidt/go-http-routing- benchmark#conclusions
ベンチマーク • cf. https://github.com/julienschmidt/go-http-routing- benchmark • GoblinՃ͠·ͨ͠ରઓΑΖ͓͘͠Ͷ͕͍͠·͢PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/97
• READMEߋ৽͍ͯ͠ͳ͍͔ΒϦετݟͨͧ͠PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/96