Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ucon-ajn33

 ucon-ajn33

いかにCloudEndpointsをやめSwaggerを愛するようになったか ajn #33
http://gcpja.connpass.com/event/30761/

Masahiro Wakame

June 08, 2016
Tweet

More Decks by Masahiro Wakame

Other Decks in Technology

Transcript

  1. ✨swagger✨ • Swagger͕Ұ൪ྑͦ͞͏ʂ • RAML, JSON Schema etc… • Open

    API Initiativeൃ଍ • Swagger࢓༷Λbaseʹ • ௕͍΋ͷʹ͸ר͔Ε͍ͨ • Qiitaʹൺֱ·ͱΊ goo.gl/BLS3uH
  2. ucon Features • net/http ͱͷྨࣅੑ • Routing • Method, Path

    Matching • Middleware • Bubble • Dependency Injection • Plugin
  3. 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}“, …
  4. Routing rule • METHOD͕Ұக͢Δ • * ࢦఆ΋Մ ݫີҰக༏ઌ • Request

    Path͕Ұக͢Δ • ෳ਺ީิ͋Δ৔߹ΑΓ௕͍અҰக • Request GET /api/user/123 • GET /api/user/{id} • ❌ GET /api/user • ઌొ࿥༏ઌ
  5. Middleware Middleware Middleware Middleware Handler ServeHTTP DI Cache-Control Cookie appengine.Context

    etc, etc… CORS Header Path, Query, Body → JSON *http.Request http.ResponseWriter
  6. 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()
 }
 }
  7. built-in middleware • RequestObjectMapper • path parameter, query paramter, post

    bodyΛObjectʹม׵͠DI • ResponseMapper • Handler͕returnͨ͠Object΍errorΛ JSONʹม׵
  8. 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))
 }
 }
 }
  9. 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))
 }
 }
 }
  10. 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) { … }
  11. 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) { … } go-endpointsͱͷޓ׵ੑ!
  12. ίʔυن໛ͷ࿩ • ຊମ 1339ߦ • 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
  13. GAE༻ϥΠϒϥϦ࡞ͬͯ·͢ • testerator github.com/favclip/testrator • UnitTestߴ଎Խ • qbg github.com/favclip/qbg •

    Datastore༻TypeSafeΫΤϦϏϧμ • smg github.com/favclip/smg • Search API༻TypeSafeϥού productionͰར༻தʂ