More Related Content
Similar to GoCon2016 spring 自作Webフレームワーク uconを作った話 (20)
More from Masahiro Wakame (20)
GoCon2016 spring 自作Webフレームワーク uconを作った話
- 7. GoCon 2015 Summer
• appengine専用じゃないけど
• jwg github.com/favclip/jwg
• genbase github.com/favclip/genbase
• GoCon 2015で話をしました!
• SlideShare goo.gl/45lZDK
- 19. Alt Cloud Endpoints
• APIs Explorer的なものが欲しい!
• サバクラの意思疎通が楽
• デバッグが楽
• コード→仕様が良い
• 仕様→コード は努力が必要(努力やだ
• クライアントコードの生成
• 変わったら壊れてほしい
- 38. まずgo-endpoints
s := &fooService{}
api, err := endpoints.RegisterService(s, "foo", "v1", "Foo API", true)
if err != nil {
panic(err.Error())
}
info := api.MethodByName("Get").Info()
info.HTTPMethod, info.Path, info.Desc = “GET", "/foo/{id}", “Fooを1件取得する"
…
type IntIDRequest struct {
ID int64 `json:"id,string"`
}
func (s *fooService) Get(r *http.Request, req *IntIDRequest) (*FooJSON, error) {
…
}
- 39. まずgo-endpoints
s := &fooService{}
api, err := endpoints.RegisterService(s, "foo", "v1", "Foo API", true)
if err != nil {
panic(err.Error())
}
info := api.MethodByName("Get").Info()
info.HTTPMethod, info.Path, info.Desc = “GET", "/foo/{id}", “Fooを1件取得する"
…
type IntIDRequest struct {
ID int64 `json:"id,string"`
}
func (s *fooService) Get(r *http.Request, req *IntIDRequest) (*FooJSON, error) {
…
}
Handler
Response
Setup
- 40. まずgo-endpoints
s := &fooService{}
api, err := endpoints.RegisterService(s, "foo", "v1", "Foo API", true)
if err != nil {
panic(err.Error())
}
info := api.MethodByName("Get").Info()
info.HTTPMethod, info.Path, info.Desc = “GET", "/foo/{id}", “Fooを1件取得する"
…
type IntIDRequest struct {
ID int64 `json:"id,string"`
}
func (s *fooService) Get(r *http.Request, req *IntIDRequest) (*FooJSON, error) {
…
}
Request
Response
闇の領域でもろもろ変換されてる
- 41. ucon Features
• net/http との類似性
• Routing
• Method, Path Matching
• Middleware
• Bubble
• Dependency Injection
• Plugin
- 44. Routing
ucon.HandleFunc(“*", “/“, …
ucon.HandleFunc(“OPTIONS", “/“, …
ucon.HandleFunc(“GET", “/“, …
ucon.HandleFunc(“POST", “/“, …
ucon.HandleFunc(“GET", “/api/user“, …
ucon.HandleFunc(“GET", “/api/user/me“, …
ucon.HandleFunc(“GET", “/api/user/{id}“, …
- 45. Routing rule
• METHODが一致する
• * 指定も可 厳密一致優先
• Request Pathが一致する
• 複数候補ある場合より長い節一致
• Request GET /api/user/123
• 🌟 GET /api/user/{id}
• ❌ GET /api/user
• 先登録優先
- 48. Middleware
type MiddlewareFunc func(b *Bubble) error
type Bubble struct {
R *http.Request
W http.ResponseWriter
Context context.Context
RequestHandler interface{}
ArgumentTypes []reflect.Type
Arguments []reflect.Value
Returns []reflect.Value
}
func (b *Bubble) Next() error {
…
}
func (b *Bubble) do() error {
hv := reflect.ValueOf(b.handler())
…
b.Returns = hv.Call(b.Arguments)
return nil
}
var httpReqType = reflect.TypeOf((*http.Request)(
var httpRespType = reflect.TypeOf((*http.Response
func HTTPRWDI() MiddlewareFunc {
return func(b *Bubble) error {
for idx, argT := range b.ArgumentTypes {
if argT == httpReqType {
b.Arguments[idx] = reflect.ValueOf(b.R)
continue
}
if argT == httpRespType {
b.Arguments[idx] = reflect.ValueOf(b.W)
continue
}
}
return b.Next()
}
}
- 52. Plugin
type pluginContainer struct {
base interface{}
}
type HandlersScannerPlugin interface {
HandlersScannerProcess(m *ServeMux, rds []*RouteDefinition) error
}
type RouteDefinition struct {
Method string
PathTemplate *PathTemplate
HandlerContainer HandlerContainer
}
func (m *ServeMux) Prepare() {
for _, plugin := range m.plugins {
used := false
if sc := plugin.HandlersScanner(); sc != nil {
err := sc.HandlersScannerProcess(m, m.router.handlers)
if err != nil {
panic(err)
}
used = true
}
if !used {
panic(fmt.Sprintf("unused plugin: %#v", plugin))
}
}
}
- 53. Plugin
type pluginContainer struct {
base interface{}
}
type HandlersScannerPlugin interface {
HandlersScannerProcess(m *ServeMux, rds []*RouteDefinition) error
}
type RouteDefinition struct {
Method string
PathTemplate *PathTemplate
HandlerContainer HandlerContainer
}
func (m *ServeMux) Prepare() {
for _, plugin := range m.plugins {
used := false
if sc := plugin.HandlersScanner(); sc != nil {
err := sc.HandlersScannerProcess(m, m.router.handlers)
if err != nil {
panic(err)
}
used = true
}
if !used {
panic(fmt.Sprintf("unused plugin: %#v", plugin))
}
}
}
- 54. swagger plugin usage
swPlugin := swagger.NewPlugin(…)
ucon.Plugin(swPlugin)
s := &fooService{}
tag := swPlugin.AddTag(&swagger.Tag{Name: "Foo", Description: ""})
var info *swagger.HandlerInfo
info = swagger.NewHandlerInfo(s.List)
ucon.Handle("GET", "/api/foo/{id}", info)
info.Description, info.Tags = "Fooを1件取得する", []string{tag.Name}
…
type IntIDRequest struct {
ID int64 `json:"id,string"`
}
func (s *fooService) Get(r *http.Request, req *IntIDRequest) (*FooJSON, error) {
…
}
- 55. go-endpoints(再掲
s := &fooService{}
api, err := endpoints.RegisterService(s, "foo", "v1", "Foo API", true)
if err != nil {
panic(err.Error())
}
info := api.MethodByName("Get").Info()
info.HTTPMethod, info.Path, info.Desc = “GET", "/foo/{id}", “Fooを1件取得する"
…
type IntIDRequest struct {
ID int64 `json:"id,string"`
}
func (s *fooService) Get(r *http.Request, req *IntIDRequest) (*FooJSON, error) {
…
}
- 56. コード規模の話
• 本体 1329行
• ls | grep .go | grep -v _test.go | xargs wc -l
• swaggerプラグイン 1138行
• find ./swagger -type f | grep .go | grep -v sample | grep -v _test.go | xargs wc -l
- 63. We are hiring 1
• 開発:テレビ朝日
• jwg, genbase 他 必要に応じて製造
• http://www.favclip.com/
• appengine/go開発者絶賛募集中!
- 64. We are hiring 2
• Topgate社も絶賛募集中です
• appengineできる人
• HTML, CSS, JS得意な人
• その他