diff --git a/README.md b/README.md new file mode 100644 index 0000000..3300e78 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# goahttpcheck + +A test helper for testing endpoints of APIs generated by Goa v2/v3. +This makes it possible to test endpoints using ivpusic/httpcheck. + +# Usage + +1. New checker. +1. Set the method handler constructor, mounter, and method endpoint in the checker. +1. Register the middleware with the checker's `Use` method (If any). +1. Call checker's `Test` method and test by ivpusic/httpcheck way. + +# Example + +**Design** + +```go +var _ = Service("calc", func() { + Description("The calc service performs operations on numbers.") + Method("add", func() { + Payload(func() { + Field(1, "a", Int, "Left operand") + Field(2, "b", Int, "Right operand") + Required("a", "b") + }) + Result(Int) + HTTP(func() { + GET("/add/{a}/{b}") + Response(StatusOK) + }) + }) +``` +**Tests** +```go +import ( +... + "calc/gen/calc" + "calc/gen/http/calc/server" +) + +func TestCalcsrvc_Add(t *testing.T) { + checker := goahttpcheck.New() + var logger log.Logger + checker.Mount(server.NewAddHandler, server.MountAddHandler, calc.NewAddEndpoint(NewCalc(&logger))) + + // see. https://github.com/ivpusic/httpcheck + checker.Test(t, http.MethodGet, "/add/1/2"). + Check(). + HasStatus(http.StatusOK). + Cb(func(r *http.Response) { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error, %v", err) + } + r.Body.Close() + if got, expected := strings.TrimSpace(string(b)), "3"; got != expected { + t.Errorf("got %+v, expected %v", b, expected) + } + }) +} +``` + +--- + +MIT \ No newline at end of file diff --git a/checker.go b/checker.go new file mode 100644 index 0000000..7e7a8f3 --- /dev/null +++ b/checker.go @@ -0,0 +1,89 @@ +package goahttpcheck + +import ( + "context" + "log" + "net/http" + "testing" + + "github.com/ivpusic/httpcheck" + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +type ( + decoder = func(*http.Request) goahttp.Decoder + encoder = func(context.Context, http.ResponseWriter) goahttp.Encoder + errorHandler = func(context.Context, http.ResponseWriter, error) + middleware = func(http.Handler) http.Handler + + HandlerBuilder func(goa.Endpoint, goahttp.Muxer, decoder, encoder, errorHandler) http.Handler + HandlerMounter func(goahttp.Muxer, http.Handler) +) + +type APIChecker struct { + Mux goahttp.Muxer + Middleware []middleware + Decoder decoder + Encoder encoder + ErrorHandler errorHandler +} + +type Option func(c *APIChecker) + +func Muxer(mux goahttp.Muxer) Option { + return func(c *APIChecker) { + c.Mux = mux + } +} + +func Decoder(dec decoder) Option { + return func(c *APIChecker) { + c.Decoder = dec + } +} + +func Encoder(enc encoder) Option { + return func(c *APIChecker) { + c.Encoder = enc + } +} + +func ErrorHandler(eh errorHandler) Option { + return func(c *APIChecker) { + c.ErrorHandler = eh + } +} + +func New(options ...Option) *APIChecker { + ret := &APIChecker{ + Mux: goahttp.NewMuxer(), + Middleware: []middleware{}, + Decoder: goahttp.RequestDecoder, + Encoder: goahttp.ResponseEncoder, + ErrorHandler: func(ctx context.Context, w http.ResponseWriter, err error) { + log.Printf("ERROR: %v", err) + }, + } + for _, v := range options { + v(ret) + } + return ret +} + +func (c *APIChecker) Mount(builder HandlerBuilder, mounter HandlerMounter, endpoint goa.Endpoint) { + handler := builder(endpoint, c.Mux, c.Decoder, c.Encoder, c.ErrorHandler) + mounter(c.Mux, handler) +} +func (c *APIChecker) Use(middleware func(http.Handler) http.Handler) { + c.Middleware = append(c.Middleware, middleware) +} + +func (c APIChecker) Test(t *testing.T, method, path string) *httpcheck.Checker { + var handler http.Handler = c.Mux + for _, v := range c.Middleware { + handler = v(handler) + } + checker := httpcheck.New(t, handler) + return checker.Test(method, path) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..610644d --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/ikawaha/goahttpcheck + +go 1.13 + +require ( + github.com/ivpusic/go-clicolor v0.0.0-20150828210804-23f0b77f328a // indirect + github.com/ivpusic/golog v0.0.0-20170608213328-28640bee649f // indirect + github.com/ivpusic/httpcheck v0.0.0-20170215120547-c49b174389ac + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect + goa.design/goa/v3 v3.0.8 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e3f0bf7 --- /dev/null +++ b/go.sum @@ -0,0 +1,136 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 h1:MGKhKyiYrvMDZsmLR/+RGffQSXwEkXgfLSA08qDn9AI= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598/go.mod h1:0FpDmbrt36utu8jEmeU05dPC9AB5tsLYVVi+ZHfyuwI= +github.com/dimfeld/httptreemux/v5 v5.0.2 h1:q+c+zKVpQocXT2OGa7dsXCX9wdeDq2TO5INqqDfKRLE= +github.com/dimfeld/httptreemux/v5 v5.0.2/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/ivpusic/go-clicolor v0.0.0-20150828210804-23f0b77f328a h1:C719vWPNIn8w0UnivhhvfIge00brg2r5BsCBmZmSWGo= +github.com/ivpusic/go-clicolor v0.0.0-20150828210804-23f0b77f328a/go.mod h1:0SFPvHdCWDlfm+uc7SYrZ30bF1sH1O1iEzBkvscKVqg= +github.com/ivpusic/golog v0.0.0-20170608213328-28640bee649f h1:FaZoTHC/do/ABnS4SLlgmILuimaaiSDcqBdGc13xJFA= +github.com/ivpusic/golog v0.0.0-20170608213328-28640bee649f/go.mod h1:EjZtQ4YORF5NXI9IZ+zcbIye4yhMFEwZjn1B0GeH88Q= +github.com/ivpusic/httpcheck v0.0.0-20170215120547-c49b174389ac h1:BezUkbHmC20WPGJC+l7LVTwnVrlxYGrKOcL9luIynYk= +github.com/ivpusic/httpcheck v0.0.0-20170215120547-c49b174389ac/go.mod h1:yk4rlbFd4qwD0pTjrlrJwS22v7XT4WrBNUv+fzqkpu4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d h1:Zj+PHjnhRYWBK6RqCDBcAhLXoi3TzC27Zad/Vn+gnVQ= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d/go.mod h1:WZy8Q5coAB1zhY9AOBJP0O6J4BuDfbupUDavKY+I3+s= +github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b/go.mod h1:Bj8LjjP0ReT1eKt5QlKjwgi5AFm5mI6O1A2G4ChI0Ag= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea/go.mod h1:eNr558nEUjP8acGw8FFjTeWvSgU1stO7FAO6eknhHe4= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +goa.design/goa/v3 v3.0.8 h1:icCp0pKZME0KtlaQSt/en8hHmFtwXYM1/AXrFyWmxVs= +goa.design/goa/v3 v3.0.8/go.mod h1:oJR8VOFa4HV7wCQv4XhPtvyknz0B3VFFRUWDdEmI0FI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191030232956-1e24073be82c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/testdata/calc.go b/testdata/calc.go new file mode 100644 index 0000000..cf2a14c --- /dev/null +++ b/testdata/calc.go @@ -0,0 +1,33 @@ +package calcapi + +import ( + "context" + "errors" + "log" + + calc "calc/gen/calc" +) + +// calc service example implementation. +// The example methods log the requests and return zero values. +type calcsrvc struct { + logger *log.Logger +} + +// NewCalc returns the calc service implementation. +func NewCalc(logger *log.Logger) calc.Service { + return &calcsrvc{logger} +} + +// Add implements add. +func (s *calcsrvc) Add(ctx context.Context, p *calc.AddPayload) (res int, err error) { + return p.A + p.B, nil +} + +// Div implements div. +func (s *calcsrvc) Div(ctx context.Context, p *calc.DivPayload) (res int, err error) { + if p.B == 0 { + return 0, calc.MakeZeroDivision(errors.New("zero division error")) + } + return p.A / p.B, nil +} diff --git a/testdata/calc_test.go b/testdata/calc_test.go new file mode 100644 index 0000000..6c6ae57 --- /dev/null +++ b/testdata/calc_test.go @@ -0,0 +1,62 @@ +package calcapi + +import ( + "encoding/json" + "io/ioutil" + "log" + "net/http" + "strings" + "testing" + + "calc/gen/calc" + "calc/gen/http/calc/server" + "github.com/ikawaha/goahttpcheck" + goa "goa.design/goa/v3/pkg" +) + +func TestCalcsrvc_Add(t *testing.T) { + checker := goahttpcheck.New() + var logger log.Logger + checker.Mount(server.NewAddHandler, server.MountAddHandler, calc.NewAddEndpoint(NewCalc(&logger))) + + // see. https://github.com/ivpusic/httpcheck + checker.Test(t, http.MethodGet, "/add/1/2"). + Check(). + HasStatus(http.StatusOK). + Cb(func(r *http.Response) { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error, %v", err) + } + r.Body.Close() + if got, expected := strings.TrimSpace(string(b)), "3"; got != expected { + t.Errorf("got %+v, expected %v", b, expected) + } + }) +} + +func TestCalcsrvc_Div(t *testing.T) { + checker := goahttpcheck.New() + + var logger log.Logger + checker.Mount(server.NewDivHandler, server.MountDivHandler, calc.NewDivEndpoint(NewCalc(&logger))) + + // see. https://github.com/ivpusic/httpcheck + checker.Test(t, "GET", "/div/1/0"). + Check(). + HasStatus(http.StatusBadRequest). + Cb(func(r *http.Response) { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error, %v", err) + } + r.Body.Close() + var resp goa.ServiceError + if err := json.Unmarshal(b, &resp); err != nil { + t.Fatalf("unexpected error, %v", err) + } + if got, expected := resp.Message, "zero division error"; got != expected { + t.Errorf("got %+v, expected %v", got, expected) + } + }) +} diff --git a/testdata/cmd/calc-cli/http.go b/testdata/cmd/calc-cli/http.go new file mode 100644 index 0000000..defbdb6 --- /dev/null +++ b/testdata/cmd/calc-cli/http.go @@ -0,0 +1,39 @@ +package main + +import ( + cli "calc/gen/http/cli/calc" + "net/http" + "time" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +func doHTTP(scheme, host string, timeout int, debug bool) (goa.Endpoint, interface{}, error) { + var ( + doer goahttp.Doer + ) + { + doer = &http.Client{Timeout: time.Duration(timeout) * time.Second} + if debug { + doer = goahttp.NewDebugDoer(doer) + } + } + + return cli.ParseEndpoint( + scheme, + host, + doer, + goahttp.RequestEncoder, + goahttp.ResponseDecoder, + debug, + ) +} + +func httpUsageCommands() string { + return cli.UsageCommands() +} + +func httpUsageExamples() string { + return cli.UsageExamples() +} diff --git a/testdata/cmd/calc-cli/main.go b/testdata/cmd/calc-cli/main.go new file mode 100644 index 0000000..325f726 --- /dev/null +++ b/testdata/cmd/calc-cli/main.go @@ -0,0 +1,120 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "net/url" + "os" + "strings" + + goa "goa.design/goa/v3/pkg" +) + +func main() { + var ( + hostF = flag.String("host", "localhost", "Server host (valid values: localhost)") + addrF = flag.String("url", "", "URL to service host") + + verboseF = flag.Bool("verbose", false, "Print request and response details") + vF = flag.Bool("v", false, "Print request and response details") + timeoutF = flag.Int("timeout", 30, "Maximum number of seconds to wait for response") + ) + flag.Usage = usage + flag.Parse() + var ( + addr string + timeout int + debug bool + ) + { + addr = *addrF + if addr == "" { + switch *hostF { + case "localhost": + addr = "http://localhost:80" + default: + fmt.Fprintf(os.Stderr, "invalid host argument: %q (valid hosts: localhost)\n", *hostF) + os.Exit(1) + } + } + timeout = *timeoutF + debug = *verboseF || *vF + } + + var ( + scheme string + host string + ) + { + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + scheme = u.Scheme + host = u.Host + } + var ( + endpoint goa.Endpoint + payload interface{} + err error + ) + { + switch scheme { + case "http", "https": + endpoint, payload, err = doHTTP(scheme, host, timeout, debug) + default: + fmt.Fprintf(os.Stderr, "invalid scheme: %q (valid schemes: grpc|http)\n", scheme) + os.Exit(1) + } + } + if err != nil { + if err == flag.ErrHelp { + os.Exit(0) + } + fmt.Fprintln(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, "run '"+os.Args[0]+" --help' for detailed usage.") + os.Exit(1) + } + + data, err := endpoint(context.Background(), payload) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + if data != nil { + m, _ := json.MarshalIndent(data, "", " ") + fmt.Println(string(m)) + } +} + +func usage() { + fmt.Fprintf(os.Stderr, `%s is a command line client for the calc API. + +Usage: + %s [-host HOST][-url URL][-timeout SECONDS][-verbose|-v] SERVICE ENDPOINT [flags] + + -host HOST: server host (localhost). valid values: localhost + -url URL: specify service URL overriding host URL (http://localhost:8080) + -timeout: maximum number of seconds to wait for response (30) + -verbose|-v: print request and response details (false) + +Commands: +%s +Additional help: + %s SERVICE [ENDPOINT] --help + +Example: +%s +`, os.Args[0], os.Args[0], indent(httpUsageCommands()), os.Args[0], indent(httpUsageExamples())) +} + +func indent(s string) string { + if s == "" { + return "" + } + return " " + strings.Replace(s, "\n", "\n ", -1) +} diff --git a/testdata/cmd/calc/http.go b/testdata/cmd/calc/http.go new file mode 100644 index 0000000..757e4f3 --- /dev/null +++ b/testdata/cmd/calc/http.go @@ -0,0 +1,109 @@ +package main + +import ( + calc "calc/gen/calc" + calcsvr "calc/gen/http/calc/server" + "context" + "log" + "net/http" + "net/url" + "os" + "sync" + "time" + + goahttp "goa.design/goa/v3/http" + httpmdlwr "goa.design/goa/v3/http/middleware" + "goa.design/goa/v3/middleware" +) + +// handleHTTPServer starts configures and starts a HTTP server on the given +// URL. It shuts down the server if any error is received in the error channel. +func handleHTTPServer(ctx context.Context, u *url.URL, calcEndpoints *calc.Endpoints, wg *sync.WaitGroup, errc chan error, logger *log.Logger, debug bool) { + + // Setup goa log adapter. + var ( + adapter middleware.Logger + ) + { + adapter = middleware.NewLogger(logger) + } + + // Provide the transport specific request decoder and response encoder. + // The goa http package has built-in support for JSON, XML and gob. + // Other encodings can be used by providing the corresponding functions, + // see goa.design/implement/encoding. + var ( + dec = goahttp.RequestDecoder + enc = goahttp.ResponseEncoder + ) + + // Build the service HTTP request multiplexer and configure it to serve + // HTTP requests to the service endpoints. + var mux goahttp.Muxer + { + mux = goahttp.NewMuxer() + } + + // Wrap the endpoints with the transport specific layers. The generated + // server packages contains code generated from the design which maps + // the service input and output data structures to HTTP requests and + // responses. + var ( + calcServer *calcsvr.Server + ) + { + eh := errorHandler(logger) + calcServer = calcsvr.New(calcEndpoints, mux, dec, enc, eh) + } + // Configure the mux. + calcsvr.Mount(mux, calcServer) + + // Wrap the multiplexer with additional middlewares. Middlewares mounted + // here apply to all the service endpoints. + var handler http.Handler = mux + { + if debug { + handler = httpmdlwr.Debug(mux, os.Stdout)(handler) + } + handler = httpmdlwr.Log(adapter)(handler) + handler = httpmdlwr.RequestID()(handler) + } + + // Start HTTP server using default configuration, change the code to + // configure the server as required by your service. + srv := &http.Server{Addr: u.Host, Handler: handler} + for _, m := range calcServer.Mounts { + logger.Printf("HTTP %q mounted on %s %s", m.Method, m.Verb, m.Pattern) + } + + (*wg).Add(1) + go func() { + defer (*wg).Done() + + // Start HTTP server in a separate goroutine. + go func() { + logger.Printf("HTTP server listening on %q", u.Host) + errc <- srv.ListenAndServe() + }() + + <-ctx.Done() + logger.Printf("shutting down HTTP server at %q", u.Host) + + // Shutdown gracefully with a 30s timeout. + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + srv.Shutdown(ctx) + }() +} + +// errorHandler returns a function that writes and logs the given error. +// The function also writes and logs the error unique ID so that it's possible +// to correlate. +func errorHandler(logger *log.Logger) func(context.Context, http.ResponseWriter, error) { + return func(ctx context.Context, w http.ResponseWriter, err error) { + id := ctx.Value(middleware.RequestIDKey).(string) + w.Write([]byte("[" + id + "] encoding: " + err.Error())) + logger.Printf("[%s] ERROR: %s", id, err.Error()) + } +} diff --git a/testdata/cmd/calc/main.go b/testdata/cmd/calc/main.go new file mode 100644 index 0000000..7179fe9 --- /dev/null +++ b/testdata/cmd/calc/main.go @@ -0,0 +1,106 @@ +package main + +import ( + calcapi "calc" + calc "calc/gen/calc" + "context" + "flag" + "fmt" + "log" + "net/url" + "os" + "os/signal" + "strings" + "sync" +) + +func main() { + // Define command line flags, add any other flag required to configure the + // service. + var ( + hostF = flag.String("host", "localhost", "Server host (valid values: localhost)") + domainF = flag.String("domain", "", "Host domain name (overrides host domain specified in service design)") + httpPortF = flag.String("http-port", "", "HTTP port (overrides host HTTP port specified in service design)") + secureF = flag.Bool("secure", false, "Use secure scheme (https or grpcs)") + dbgF = flag.Bool("debug", false, "Log request and response bodies") + ) + flag.Parse() + + // Setup logger. Replace logger with your own log package of choice. + var ( + logger *log.Logger + ) + { + logger = log.New(os.Stderr, "[calcapi] ", log.Ltime) + } + + // Initialize the services. + var ( + calcSvc calc.Service + ) + { + calcSvc = calcapi.NewCalc(logger) + } + + // Wrap the services in endpoints that can be invoked from other services + // potentially running in different processes. + var ( + calcEndpoints *calc.Endpoints + ) + { + calcEndpoints = calc.NewEndpoints(calcSvc) + } + + // Create channel used by both the signal handler and server goroutines + // to notify the main goroutine when to stop the server. + errc := make(chan error) + + // Setup interrupt handler. This optional step configures the process so + // that SIGINT and SIGTERM signals cause the services to stop gracefully. + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + errc <- fmt.Errorf("%s", <-c) + }() + + var wg sync.WaitGroup + ctx, cancel := context.WithCancel(context.Background()) + + // Start the servers and send errors (if any) to the error channel. + switch *hostF { + case "localhost": + { + addr := "http://localhost:80" + u, err := url.Parse(addr) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err) + os.Exit(1) + } + if *secureF { + u.Scheme = "https" + } + if *domainF != "" { + u.Host = *domainF + } + if *httpPortF != "" { + h := strings.Split(u.Host, ":")[0] + u.Host = h + ":" + *httpPortF + } else if u.Port() == "" { + u.Host += ":80" + } + handleHTTPServer(ctx, u, calcEndpoints, &wg, errc, logger, *dbgF) + } + + default: + fmt.Fprintf(os.Stderr, "invalid host argument: %q (valid hosts: localhost)\n", *hostF) + } + + // Wait for signal. + logger.Printf("exiting (%v)", <-errc) + + // Send cancellation signal to the goroutines. + cancel() + + wg.Wait() + logger.Println("exited") +} diff --git a/testdata/design/design.go b/testdata/design/design.go new file mode 100644 index 0000000..e80eb61 --- /dev/null +++ b/testdata/design/design.go @@ -0,0 +1,36 @@ +package design + +import ( + . "goa.design/goa/v3/dsl" +) + +var _ = Service("calc", func() { + Description("The calc service performs operations on numbers.") + Method("add", func() { + Payload(func() { + Field(1, "a", Int, "Left operand") + Field(2, "b", Int, "Right operand") + Required("a", "b") + }) + Result(Int) + HTTP(func() { + GET("/add/{a}/{b}") + Response(StatusOK) + }) + }) + + Method("div", func() { + Error("zero_division", ErrorResult) + Payload(func() { + Field(1, "a", Int, "Left operand") + Field(2, "b", Int, "Right operand") + Required("a", "b") + }) + Result(Int) + HTTP(func() { + GET("/div/{a}/{b}") + Response(StatusOK) + Response("zero_division", StatusBadRequest) + }) + }) +}) diff --git a/testdata/gen/calc/client.go b/testdata/gen/calc/client.go new file mode 100644 index 0000000..a3156cb --- /dev/null +++ b/testdata/gen/calc/client.go @@ -0,0 +1,51 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc client +// +// Command: +// $ goa gen calc/design + +package calc + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// Client is the "calc" service client. +type Client struct { + AddEndpoint goa.Endpoint + DivEndpoint goa.Endpoint +} + +// NewClient initializes a "calc" service client given the endpoints. +func NewClient(add, div goa.Endpoint) *Client { + return &Client{ + AddEndpoint: add, + DivEndpoint: div, + } +} + +// Add calls the "add" endpoint of the "calc" service. +func (c *Client) Add(ctx context.Context, p *AddPayload) (res int, err error) { + var ires interface{} + ires, err = c.AddEndpoint(ctx, p) + if err != nil { + return + } + return ires.(int), nil +} + +// Div calls the "div" endpoint of the "calc" service. +// Div may return the following errors: +// - "zero_division" (type *goa.ServiceError) +// - error: internal error +func (c *Client) Div(ctx context.Context, p *DivPayload) (res int, err error) { + var ires interface{} + ires, err = c.DivEndpoint(ctx, p) + if err != nil { + return + } + return ires.(int), nil +} diff --git a/testdata/gen/calc/endpoints.go b/testdata/gen/calc/endpoints.go new file mode 100644 index 0000000..c09dd94 --- /dev/null +++ b/testdata/gen/calc/endpoints.go @@ -0,0 +1,52 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc endpoints +// +// Command: +// $ goa gen calc/design + +package calc + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// Endpoints wraps the "calc" service endpoints. +type Endpoints struct { + Add goa.Endpoint + Div goa.Endpoint +} + +// NewEndpoints wraps the methods of the "calc" service with endpoints. +func NewEndpoints(s Service) *Endpoints { + return &Endpoints{ + Add: NewAddEndpoint(s), + Div: NewDivEndpoint(s), + } +} + +// Use applies the given middleware to all the "calc" service endpoints. +func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { + e.Add = m(e.Add) + e.Div = m(e.Div) +} + +// NewAddEndpoint returns an endpoint function that calls the method "add" of +// service "calc". +func NewAddEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*AddPayload) + return s.Add(ctx, p) + } +} + +// NewDivEndpoint returns an endpoint function that calls the method "div" of +// service "calc". +func NewDivEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*DivPayload) + return s.Div(ctx, p) + } +} diff --git a/testdata/gen/calc/service.go b/testdata/gen/calc/service.go new file mode 100644 index 0000000..8018d47 --- /dev/null +++ b/testdata/gen/calc/service.go @@ -0,0 +1,57 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc service +// +// Command: +// $ goa gen calc/design + +package calc + +import ( + "context" + + goa "goa.design/goa/v3/pkg" +) + +// The calc service performs operations on numbers. +type Service interface { + // Add implements add. + Add(context.Context, *AddPayload) (res int, err error) + // Div implements div. + Div(context.Context, *DivPayload) (res int, err error) +} + +// ServiceName is the name of the service as defined in the design. This is the +// same value that is set in the endpoint request contexts under the ServiceKey +// key. +const ServiceName = "calc" + +// MethodNames lists the service method names as defined in the design. These +// are the same values that are set in the endpoint request contexts under the +// MethodKey key. +var MethodNames = [2]string{"add", "div"} + +// AddPayload is the payload type of the calc service add method. +type AddPayload struct { + // Left operand + A int + // Right operand + B int +} + +// DivPayload is the payload type of the calc service div method. +type DivPayload struct { + // Left operand + A int + // Right operand + B int +} + +// MakeZeroDivision builds a goa.ServiceError from an error. +func MakeZeroDivision(err error) *goa.ServiceError { + return &goa.ServiceError{ + Name: "zero_division", + ID: goa.NewErrorID(), + Message: err.Error(), + } +} diff --git a/testdata/gen/http/calc/client/cli.go b/testdata/gen/http/calc/client/cli.go new file mode 100644 index 0000000..3cd647c --- /dev/null +++ b/testdata/gen/http/calc/client/cli.go @@ -0,0 +1,70 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP client CLI support package +// +// Command: +// $ goa gen calc/design + +package client + +import ( + calc "calc/gen/calc" + "fmt" + "strconv" +) + +// BuildAddPayload builds the payload for the calc add endpoint from CLI flags. +func BuildAddPayload(calcAddA string, calcAddB string) (*calc.AddPayload, error) { + var err error + var a int + { + var v int64 + v, err = strconv.ParseInt(calcAddA, 10, 64) + a = int(v) + if err != nil { + return nil, fmt.Errorf("invalid value for a, must be INT") + } + } + var b int + { + var v int64 + v, err = strconv.ParseInt(calcAddB, 10, 64) + b = int(v) + if err != nil { + return nil, fmt.Errorf("invalid value for b, must be INT") + } + } + payload := &calc.AddPayload{ + A: a, + B: b, + } + return payload, nil +} + +// BuildDivPayload builds the payload for the calc div endpoint from CLI flags. +func BuildDivPayload(calcDivA string, calcDivB string) (*calc.DivPayload, error) { + var err error + var a int + { + var v int64 + v, err = strconv.ParseInt(calcDivA, 10, 64) + a = int(v) + if err != nil { + return nil, fmt.Errorf("invalid value for a, must be INT") + } + } + var b int + { + var v int64 + v, err = strconv.ParseInt(calcDivB, 10, 64) + b = int(v) + if err != nil { + return nil, fmt.Errorf("invalid value for b, must be INT") + } + } + payload := &calc.DivPayload{ + A: a, + B: b, + } + return payload, nil +} diff --git a/testdata/gen/http/calc/client/client.go b/testdata/gen/http/calc/client/client.go new file mode 100644 index 0000000..c7a5f3f --- /dev/null +++ b/testdata/gen/http/calc/client/client.go @@ -0,0 +1,94 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc client HTTP transport +// +// Command: +// $ goa gen calc/design + +package client + +import ( + "context" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Client lists the calc service endpoint HTTP clients. +type Client struct { + // Add Doer is the HTTP client used to make requests to the add endpoint. + AddDoer goahttp.Doer + + // Div Doer is the HTTP client used to make requests to the div endpoint. + DivDoer goahttp.Doer + + // RestoreResponseBody controls whether the response bodies are reset after + // decoding so they can be read again. + RestoreResponseBody bool + + scheme string + host string + encoder func(*http.Request) goahttp.Encoder + decoder func(*http.Response) goahttp.Decoder +} + +// NewClient instantiates HTTP clients for all the calc service servers. +func NewClient( + scheme string, + host string, + doer goahttp.Doer, + enc func(*http.Request) goahttp.Encoder, + dec func(*http.Response) goahttp.Decoder, + restoreBody bool, +) *Client { + return &Client{ + AddDoer: doer, + DivDoer: doer, + RestoreResponseBody: restoreBody, + scheme: scheme, + host: host, + decoder: dec, + encoder: enc, + } +} + +// Add returns an endpoint that makes HTTP requests to the calc service add +// server. +func (c *Client) Add() goa.Endpoint { + var ( + decodeResponse = DecodeAddResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildAddRequest(ctx, v) + if err != nil { + return nil, err + } + resp, err := c.AddDoer.Do(req) + + if err != nil { + return nil, goahttp.ErrRequestError("calc", "add", err) + } + return decodeResponse(resp) + } +} + +// Div returns an endpoint that makes HTTP requests to the calc service div +// server. +func (c *Client) Div() goa.Endpoint { + var ( + decodeResponse = DecodeDivResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildDivRequest(ctx, v) + if err != nil { + return nil, err + } + resp, err := c.DivDoer.Do(req) + + if err != nil { + return nil, goahttp.ErrRequestError("calc", "div", err) + } + return decodeResponse(resp) + } +} diff --git a/testdata/gen/http/calc/client/encode_decode.go b/testdata/gen/http/calc/client/encode_decode.go new file mode 100644 index 0000000..35a36a1 --- /dev/null +++ b/testdata/gen/http/calc/client/encode_decode.go @@ -0,0 +1,160 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP client encoders and decoders +// +// Command: +// $ goa gen calc/design + +package client + +import ( + "bytes" + calc "calc/gen/calc" + "context" + "io/ioutil" + "net/http" + "net/url" + + goahttp "goa.design/goa/v3/http" +) + +// BuildAddRequest instantiates a HTTP request object with method and path set +// to call the "calc" service "add" endpoint +func (c *Client) BuildAddRequest(ctx context.Context, v interface{}) (*http.Request, error) { + var ( + a int + b int + ) + { + p, ok := v.(*calc.AddPayload) + if !ok { + return nil, goahttp.ErrInvalidType("calc", "add", "*calc.AddPayload", v) + } + a = p.A + b = p.B + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: AddCalcPath(a, b)} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("calc", "add", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// DecodeAddResponse returns a decoder for responses returned by the calc add +// endpoint. restoreBody controls whether the response body should be restored +// after having been read. +func DecodeAddResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body int + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("calc", "add", err) + } + return body, nil + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("calc", "add", resp.StatusCode, string(body)) + } + } +} + +// BuildDivRequest instantiates a HTTP request object with method and path set +// to call the "calc" service "div" endpoint +func (c *Client) BuildDivRequest(ctx context.Context, v interface{}) (*http.Request, error) { + var ( + a int + b int + ) + { + p, ok := v.(*calc.DivPayload) + if !ok { + return nil, goahttp.ErrInvalidType("calc", "div", "*calc.DivPayload", v) + } + a = p.A + b = p.B + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: DivCalcPath(a, b)} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("calc", "div", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// DecodeDivResponse returns a decoder for responses returned by the calc div +// endpoint. restoreBody controls whether the response body should be restored +// after having been read. +// DecodeDivResponse may return the following errors: +// - "zero_division" (type *goa.ServiceError): http.StatusBadRequest +// - error: internal error +func DecodeDivResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body int + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("calc", "div", err) + } + return body, nil + case http.StatusBadRequest: + var ( + body DivZeroDivisionResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("calc", "div", err) + } + err = ValidateDivZeroDivisionResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("calc", "div", err) + } + return nil, NewDivZeroDivision(&body) + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("calc", "div", resp.StatusCode, string(body)) + } + } +} diff --git a/testdata/gen/http/calc/client/paths.go b/testdata/gen/http/calc/client/paths.go new file mode 100644 index 0000000..adfc619 --- /dev/null +++ b/testdata/gen/http/calc/client/paths.go @@ -0,0 +1,22 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// HTTP request path constructors for the calc service. +// +// Command: +// $ goa gen calc/design + +package client + +import ( + "fmt" +) + +// AddCalcPath returns the URL path to the calc service add HTTP endpoint. +func AddCalcPath(a int, b int) string { + return fmt.Sprintf("/add/%v/%v", a, b) +} + +// DivCalcPath returns the URL path to the calc service div HTTP endpoint. +func DivCalcPath(a int, b int) string { + return fmt.Sprintf("/div/%v/%v", a, b) +} diff --git a/testdata/gen/http/calc/client/types.go b/testdata/gen/http/calc/client/types.go new file mode 100644 index 0000000..fb42462 --- /dev/null +++ b/testdata/gen/http/calc/client/types.go @@ -0,0 +1,67 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP client types +// +// Command: +// $ goa gen calc/design + +package client + +import ( + goa "goa.design/goa/v3/pkg" +) + +// DivZeroDivisionResponseBody is the type of the "calc" service "div" endpoint +// HTTP response body for the "zero_division" error. +type DivZeroDivisionResponseBody struct { + // Name is the name of this class of errors. + Name *string `form:"name,omitempty" json:"name,omitempty" xml:"name,omitempty"` + // ID is a unique identifier for this particular occurrence of the problem. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Message is a human-readable explanation specific to this occurrence of the + // problem. + Message *string `form:"message,omitempty" json:"message,omitempty" xml:"message,omitempty"` + // Is the error temporary? + Temporary *bool `form:"temporary,omitempty" json:"temporary,omitempty" xml:"temporary,omitempty"` + // Is the error a timeout? + Timeout *bool `form:"timeout,omitempty" json:"timeout,omitempty" xml:"timeout,omitempty"` + // Is the error a server-side fault? + Fault *bool `form:"fault,omitempty" json:"fault,omitempty" xml:"fault,omitempty"` +} + +// NewDivZeroDivision builds a calc service div endpoint zero_division error. +func NewDivZeroDivision(body *DivZeroDivisionResponseBody) *goa.ServiceError { + v := &goa.ServiceError{ + Name: *body.Name, + ID: *body.ID, + Message: *body.Message, + Temporary: *body.Temporary, + Timeout: *body.Timeout, + Fault: *body.Fault, + } + return v +} + +// ValidateDivZeroDivisionResponseBody runs the validations defined on +// div_zero_division_response_body +func ValidateDivZeroDivisionResponseBody(body *DivZeroDivisionResponseBody) (err error) { + if body.Name == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("name", "body")) + } + if body.ID == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) + } + if body.Message == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("message", "body")) + } + if body.Temporary == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("temporary", "body")) + } + if body.Timeout == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("timeout", "body")) + } + if body.Fault == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("fault", "body")) + } + return +} diff --git a/testdata/gen/http/calc/server/encode_decode.go b/testdata/gen/http/calc/server/encode_decode.go new file mode 100644 index 0000000..1ed785c --- /dev/null +++ b/testdata/gen/http/calc/server/encode_decode.go @@ -0,0 +1,136 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP server encoders and decoders +// +// Command: +// $ goa gen calc/design + +package server + +import ( + "context" + "net/http" + "strconv" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// EncodeAddResponse returns an encoder for responses returned by the calc add +// endpoint. +func EncodeAddResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res := v.(int) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeAddRequest returns a decoder for requests sent to the calc add +// endpoint. +func DecodeAddRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + var ( + a int + b int + err error + + params = mux.Vars(r) + ) + { + aRaw := params["a"] + v, err2 := strconv.ParseInt(aRaw, 10, strconv.IntSize) + if err2 != nil { + err = goa.MergeErrors(err, goa.InvalidFieldTypeError("a", aRaw, "integer")) + } + a = int(v) + } + { + bRaw := params["b"] + v, err2 := strconv.ParseInt(bRaw, 10, strconv.IntSize) + if err2 != nil { + err = goa.MergeErrors(err, goa.InvalidFieldTypeError("b", bRaw, "integer")) + } + b = int(v) + } + if err != nil { + return nil, err + } + payload := NewAddPayload(a, b) + + return payload, nil + } +} + +// EncodeDivResponse returns an encoder for responses returned by the calc div +// endpoint. +func EncodeDivResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res := v.(int) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeDivRequest returns a decoder for requests sent to the calc div +// endpoint. +func DecodeDivRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + var ( + a int + b int + err error + + params = mux.Vars(r) + ) + { + aRaw := params["a"] + v, err2 := strconv.ParseInt(aRaw, 10, strconv.IntSize) + if err2 != nil { + err = goa.MergeErrors(err, goa.InvalidFieldTypeError("a", aRaw, "integer")) + } + a = int(v) + } + { + bRaw := params["b"] + v, err2 := strconv.ParseInt(bRaw, 10, strconv.IntSize) + if err2 != nil { + err = goa.MergeErrors(err, goa.InvalidFieldTypeError("b", bRaw, "integer")) + } + b = int(v) + } + if err != nil { + return nil, err + } + payload := NewDivPayload(a, b) + + return payload, nil + } +} + +// EncodeDivError returns an encoder for errors returned by the div calc +// endpoint. +func EncodeDivError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, error) error { + encodeError := goahttp.ErrorEncoder(encoder) + return func(ctx context.Context, w http.ResponseWriter, v error) error { + en, ok := v.(ErrorNamer) + if !ok { + return encodeError(ctx, w, v) + } + switch en.ErrorName() { + case "zero_division": + res := v.(*goa.ServiceError) + enc := encoder(ctx, w) + body := NewDivZeroDivisionResponseBody(res) + w.Header().Set("goa-error", "zero_division") + w.WriteHeader(http.StatusBadRequest) + return enc.Encode(body) + default: + return encodeError(ctx, w, v) + } + } +} diff --git a/testdata/gen/http/calc/server/paths.go b/testdata/gen/http/calc/server/paths.go new file mode 100644 index 0000000..d7994f5 --- /dev/null +++ b/testdata/gen/http/calc/server/paths.go @@ -0,0 +1,22 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// HTTP request path constructors for the calc service. +// +// Command: +// $ goa gen calc/design + +package server + +import ( + "fmt" +) + +// AddCalcPath returns the URL path to the calc service add HTTP endpoint. +func AddCalcPath(a int, b int) string { + return fmt.Sprintf("/add/%v/%v", a, b) +} + +// DivCalcPath returns the URL path to the calc service div HTTP endpoint. +func DivCalcPath(a int, b int) string { + return fmt.Sprintf("/div/%v/%v", a, b) +} diff --git a/testdata/gen/http/calc/server/server.go b/testdata/gen/http/calc/server/server.go new file mode 100644 index 0000000..e07657a --- /dev/null +++ b/testdata/gen/http/calc/server/server.go @@ -0,0 +1,178 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP server +// +// Command: +// $ goa gen calc/design + +package server + +import ( + calc "calc/gen/calc" + "context" + "net/http" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// Server lists the calc service endpoint HTTP handlers. +type Server struct { + Mounts []*MountPoint + Add http.Handler + Div http.Handler +} + +// ErrorNamer is an interface implemented by generated error structs that +// exposes the name of the error as defined in the design. +type ErrorNamer interface { + ErrorName() string +} + +// MountPoint holds information about the mounted endpoints. +type MountPoint struct { + // Method is the name of the service method served by the mounted HTTP handler. + Method string + // Verb is the HTTP method used to match requests to the mounted handler. + Verb string + // Pattern is the HTTP request path pattern used to match requests to the + // mounted handler. + Pattern string +} + +// New instantiates HTTP handlers for all the calc service endpoints. +func New( + e *calc.Endpoints, + mux goahttp.Muxer, + dec func(*http.Request) goahttp.Decoder, + enc func(context.Context, http.ResponseWriter) goahttp.Encoder, + eh func(context.Context, http.ResponseWriter, error), +) *Server { + return &Server{ + Mounts: []*MountPoint{ + {"Add", "GET", "/add/{a}/{b}"}, + {"Div", "GET", "/div/{a}/{b}"}, + }, + Add: NewAddHandler(e.Add, mux, dec, enc, eh), + Div: NewDivHandler(e.Div, mux, dec, enc, eh), + } +} + +// Service returns the name of the service served. +func (s *Server) Service() string { return "calc" } + +// Use wraps the server handlers with the given middleware. +func (s *Server) Use(m func(http.Handler) http.Handler) { + s.Add = m(s.Add) + s.Div = m(s.Div) +} + +// Mount configures the mux to serve the calc endpoints. +func Mount(mux goahttp.Muxer, h *Server) { + MountAddHandler(mux, h.Add) + MountDivHandler(mux, h.Div) +} + +// MountAddHandler configures the mux to serve the "calc" service "add" +// endpoint. +func MountAddHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/add/{a}/{b}", f) +} + +// NewAddHandler creates a HTTP handler which loads the HTTP request and calls +// the "calc" service "add" endpoint. +func NewAddHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + dec func(*http.Request) goahttp.Decoder, + enc func(context.Context, http.ResponseWriter) goahttp.Encoder, + eh func(context.Context, http.ResponseWriter, error), +) http.Handler { + var ( + decodeRequest = DecodeAddRequest(mux, dec) + encodeResponse = EncodeAddResponse(enc) + encodeError = goahttp.ErrorEncoder(enc) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "add") + ctx = context.WithValue(ctx, goa.ServiceKey, "calc") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + eh(ctx, w, err) + } + return + } + + res, err := endpoint(ctx, payload) + + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + eh(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + eh(ctx, w, err) + } + }) +} + +// MountDivHandler configures the mux to serve the "calc" service "div" +// endpoint. +func MountDivHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/div/{a}/{b}", f) +} + +// NewDivHandler creates a HTTP handler which loads the HTTP request and calls +// the "calc" service "div" endpoint. +func NewDivHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + dec func(*http.Request) goahttp.Decoder, + enc func(context.Context, http.ResponseWriter) goahttp.Encoder, + eh func(context.Context, http.ResponseWriter, error), +) http.Handler { + var ( + decodeRequest = DecodeDivRequest(mux, dec) + encodeResponse = EncodeDivResponse(enc) + encodeError = EncodeDivError(enc) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "div") + ctx = context.WithValue(ctx, goa.ServiceKey, "calc") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + eh(ctx, w, err) + } + return + } + + res, err := endpoint(ctx, payload) + + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + eh(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + eh(ctx, w, err) + } + }) +} diff --git a/testdata/gen/http/calc/server/types.go b/testdata/gen/http/calc/server/types.go new file mode 100644 index 0000000..2791438 --- /dev/null +++ b/testdata/gen/http/calc/server/types.go @@ -0,0 +1,62 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP server types +// +// Command: +// $ goa gen calc/design + +package server + +import ( + calc "calc/gen/calc" + + goa "goa.design/goa/v3/pkg" +) + +// DivZeroDivisionResponseBody is the type of the "calc" service "div" endpoint +// HTTP response body for the "zero_division" error. +type DivZeroDivisionResponseBody struct { + // Name is the name of this class of errors. + Name string `form:"name" json:"name" xml:"name"` + // ID is a unique identifier for this particular occurrence of the problem. + ID string `form:"id" json:"id" xml:"id"` + // Message is a human-readable explanation specific to this occurrence of the + // problem. + Message string `form:"message" json:"message" xml:"message"` + // Is the error temporary? + Temporary bool `form:"temporary" json:"temporary" xml:"temporary"` + // Is the error a timeout? + Timeout bool `form:"timeout" json:"timeout" xml:"timeout"` + // Is the error a server-side fault? + Fault bool `form:"fault" json:"fault" xml:"fault"` +} + +// NewDivZeroDivisionResponseBody builds the HTTP response body from the result +// of the "div" endpoint of the "calc" service. +func NewDivZeroDivisionResponseBody(res *goa.ServiceError) *DivZeroDivisionResponseBody { + body := &DivZeroDivisionResponseBody{ + Name: res.Name, + ID: res.ID, + Message: res.Message, + Temporary: res.Temporary, + Timeout: res.Timeout, + Fault: res.Fault, + } + return body +} + +// NewAddPayload builds a calc service add endpoint payload. +func NewAddPayload(a int, b int) *calc.AddPayload { + return &calc.AddPayload{ + A: a, + B: b, + } +} + +// NewDivPayload builds a calc service div endpoint payload. +func NewDivPayload(a int, b int) *calc.DivPayload { + return &calc.DivPayload{ + A: a, + B: b, + } +} diff --git a/testdata/gen/http/cli/calc/cli.go b/testdata/gen/http/cli/calc/cli.go new file mode 100644 index 0000000..193892d --- /dev/null +++ b/testdata/gen/http/cli/calc/cli.go @@ -0,0 +1,177 @@ +// Code generated by goa v3.0.8, DO NOT EDIT. +// +// calc HTTP client CLI support package +// +// Command: +// $ goa gen calc/design + +package cli + +import ( + calcc "calc/gen/http/calc/client" + "flag" + "fmt" + "net/http" + "os" + + goahttp "goa.design/goa/v3/http" + goa "goa.design/goa/v3/pkg" +) + +// UsageCommands returns the set of commands and sub-commands using the format +// +// command (subcommand1|subcommand2|...) +// +func UsageCommands() string { + return `calc (add|div) +` +} + +// UsageExamples produces an example of a valid invocation of the CLI tool. +func UsageExamples() string { + return os.Args[0] + ` calc add --a 3793862871819669726 --b 8399553735696626949` + "\n" + + "" +} + +// ParseEndpoint returns the endpoint and payload as specified on the command +// line. +func ParseEndpoint( + scheme, host string, + doer goahttp.Doer, + enc func(*http.Request) goahttp.Encoder, + dec func(*http.Response) goahttp.Decoder, + restore bool, +) (goa.Endpoint, interface{}, error) { + var ( + calcFlags = flag.NewFlagSet("calc", flag.ContinueOnError) + + calcAddFlags = flag.NewFlagSet("add", flag.ExitOnError) + calcAddAFlag = calcAddFlags.String("a", "REQUIRED", "Left operand") + calcAddBFlag = calcAddFlags.String("b", "REQUIRED", "Right operand") + + calcDivFlags = flag.NewFlagSet("div", flag.ExitOnError) + calcDivAFlag = calcDivFlags.String("a", "REQUIRED", "Left operand") + calcDivBFlag = calcDivFlags.String("b", "REQUIRED", "Right operand") + ) + calcFlags.Usage = calcUsage + calcAddFlags.Usage = calcAddUsage + calcDivFlags.Usage = calcDivUsage + + if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { + return nil, nil, err + } + + if flag.NArg() < 2 { // two non flag args are required: SERVICE and ENDPOINT (aka COMMAND) + return nil, nil, fmt.Errorf("not enough arguments") + } + + var ( + svcn string + svcf *flag.FlagSet + ) + { + svcn = flag.Arg(0) + switch svcn { + case "calc": + svcf = calcFlags + default: + return nil, nil, fmt.Errorf("unknown service %q", svcn) + } + } + if err := svcf.Parse(flag.Args()[1:]); err != nil { + return nil, nil, err + } + + var ( + epn string + epf *flag.FlagSet + ) + { + epn = svcf.Arg(0) + switch svcn { + case "calc": + switch epn { + case "add": + epf = calcAddFlags + + case "div": + epf = calcDivFlags + + } + + } + } + if epf == nil { + return nil, nil, fmt.Errorf("unknown %q endpoint %q", svcn, epn) + } + + // Parse endpoint flags if any + if svcf.NArg() > 1 { + if err := epf.Parse(svcf.Args()[1:]); err != nil { + return nil, nil, err + } + } + + var ( + data interface{} + endpoint goa.Endpoint + err error + ) + { + switch svcn { + case "calc": + c := calcc.NewClient(scheme, host, doer, enc, dec, restore) + switch epn { + case "add": + endpoint = c.Add() + data, err = calcc.BuildAddPayload(*calcAddAFlag, *calcAddBFlag) + case "div": + endpoint = c.Div() + data, err = calcc.BuildDivPayload(*calcDivAFlag, *calcDivBFlag) + } + } + } + if err != nil { + return nil, nil, err + } + + return endpoint, data, nil +} + +// calcUsage displays the usage of the calc command and its subcommands. +func calcUsage() { + fmt.Fprintf(os.Stderr, `The calc service performs operations on numbers. +Usage: + %s [globalflags] calc COMMAND [flags] + +COMMAND: + add: Add implements add. + div: Div implements div. + +Additional help: + %s calc COMMAND --help +`, os.Args[0], os.Args[0]) +} +func calcAddUsage() { + fmt.Fprintf(os.Stderr, `%s [flags] calc add -a INT -b INT + +Add implements add. + -a INT: Left operand + -b INT: Right operand + +Example: + `+os.Args[0]+` calc add --a 3793862871819669726 --b 8399553735696626949 +`, os.Args[0]) +} + +func calcDivUsage() { + fmt.Fprintf(os.Stderr, `%s [flags] calc div -a INT -b INT + +Div implements div. + -a INT: Left operand + -b INT: Right operand + +Example: + `+os.Args[0]+` calc div --a 5401762099778430809 --b 1918630006328122782 +`, os.Args[0]) +} diff --git a/testdata/gen/http/openapi.json b/testdata/gen/http/openapi.json new file mode 100644 index 0000000..4ed745d --- /dev/null +++ b/testdata/gen/http/openapi.json @@ -0,0 +1 @@ +{"swagger":"2.0","info":{"title":"","version":""},"host":"localhost:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/add/{a}/{b}":{"get":{"tags":["calc"],"summary":"add calc","operationId":"calc#add","parameters":[{"name":"a","in":"path","description":"Left operand","required":true,"type":"integer"},{"name":"b","in":"path","description":"Right operand","required":true,"type":"integer"}],"responses":{"200":{"description":"OK response.","schema":{"type":"integer","format":"int64"}}},"schemes":["http"]}},"/div/{a}/{b}":{"get":{"tags":["calc"],"summary":"div calc","operationId":"calc#div","parameters":[{"name":"a","in":"path","description":"Left operand","required":true,"type":"integer"},{"name":"b","in":"path","description":"Right operand","required":true,"type":"integer"}],"responses":{"200":{"description":"OK response.","schema":{"type":"integer","format":"int64"}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/CalcDivZeroDivisionResponseBody"}}},"schemes":["http"]}}},"definitions":{"CalcDivZeroDivisionResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"div_zero_division_response_body result type (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]}}} \ No newline at end of file diff --git a/testdata/gen/http/openapi.yaml b/testdata/gen/http/openapi.yaml new file mode 100644 index 0000000..4c81bb2 --- /dev/null +++ b/testdata/gen/http/openapi.yaml @@ -0,0 +1,114 @@ +swagger: "2.0" +info: + title: "" + version: "" +host: localhost:80 +consumes: +- application/json +- application/xml +- application/gob +produces: +- application/json +- application/xml +- application/gob +paths: + /add/{a}/{b}: + get: + tags: + - calc + summary: add calc + operationId: calc#add + parameters: + - name: a + in: path + description: Left operand + required: true + type: integer + - name: b + in: path + description: Right operand + required: true + type: integer + responses: + "200": + description: OK response. + schema: + type: integer + format: int64 + schemes: + - http + /div/{a}/{b}: + get: + tags: + - calc + summary: div calc + operationId: calc#div + parameters: + - name: a + in: path + description: Left operand + required: true + type: integer + - name: b + in: path + description: Right operand + required: true + type: integer + responses: + "200": + description: OK response. + schema: + type: integer + format: int64 + "400": + description: Bad Request response. + schema: + $ref: '#/definitions/CalcDivZeroDivisionResponseBody' + schemes: + - http +definitions: + CalcDivZeroDivisionResponseBody: + title: 'Mediatype identifier: application/vnd.goa.error; view=default' + type: object + properties: + fault: + type: boolean + description: Is the error a server-side fault? + example: true + id: + type: string + description: ID is a unique identifier for this particular occurrence of the + problem. + example: 123abc + message: + type: string + description: Message is a human-readable explanation specific to this occurrence + of the problem. + example: parameter 'p' must be an integer + name: + type: string + description: Name is the name of this class of errors. + example: bad_request + temporary: + type: boolean + description: Is the error temporary? + example: false + timeout: + type: boolean + description: Is the error a timeout? + example: false + description: div_zero_division_response_body result type (default view) + example: + fault: true + id: 123abc + message: parameter 'p' must be an integer + name: bad_request + temporary: true + timeout: true + required: + - name + - id + - message + - temporary + - timeout + - fault diff --git a/testdata/go.mod b/testdata/go.mod new file mode 100644 index 0000000..14ebc57 --- /dev/null +++ b/testdata/go.mod @@ -0,0 +1,10 @@ +module calc + +go 1.13 + +replace github.com/ikawaha/goahttpcheck => ../ + +require ( + github.com/ikawaha/goahttpcheck v0.0.0-00010101000000-000000000000 + goa.design/goa/v3 v3.0.8 +) diff --git a/testdata/go.sum b/testdata/go.sum new file mode 100644 index 0000000..3fde591 --- /dev/null +++ b/testdata/go.sum @@ -0,0 +1,139 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 h1:MGKhKyiYrvMDZsmLR/+RGffQSXwEkXgfLSA08qDn9AI= +github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598/go.mod h1:0FpDmbrt36utu8jEmeU05dPC9AB5tsLYVVi+ZHfyuwI= +github.com/dimfeld/httptreemux/v5 v5.0.2 h1:q+c+zKVpQocXT2OGa7dsXCX9wdeDq2TO5INqqDfKRLE= +github.com/dimfeld/httptreemux/v5 v5.0.2/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/ivpusic/go-clicolor v0.0.0-20150828210804-23f0b77f328a h1:C719vWPNIn8w0UnivhhvfIge00brg2r5BsCBmZmSWGo= +github.com/ivpusic/go-clicolor v0.0.0-20150828210804-23f0b77f328a/go.mod h1:0SFPvHdCWDlfm+uc7SYrZ30bF1sH1O1iEzBkvscKVqg= +github.com/ivpusic/golog v0.0.0-20170608213328-28640bee649f h1:FaZoTHC/do/ABnS4SLlgmILuimaaiSDcqBdGc13xJFA= +github.com/ivpusic/golog v0.0.0-20170608213328-28640bee649f/go.mod h1:EjZtQ4YORF5NXI9IZ+zcbIye4yhMFEwZjn1B0GeH88Q= +github.com/ivpusic/httpcheck v0.0.0-20170215120547-c49b174389ac h1:BezUkbHmC20WPGJC+l7LVTwnVrlxYGrKOcL9luIynYk= +github.com/ivpusic/httpcheck v0.0.0-20170215120547-c49b174389ac/go.mod h1:yk4rlbFd4qwD0pTjrlrJwS22v7XT4WrBNUv+fzqkpu4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d h1:Zj+PHjnhRYWBK6RqCDBcAhLXoi3TzC27Zad/Vn+gnVQ= +github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d/go.mod h1:WZy8Q5coAB1zhY9AOBJP0O6J4BuDfbupUDavKY+I3+s= +github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b/go.mod h1:Bj8LjjP0ReT1eKt5QlKjwgi5AFm5mI6O1A2G4ChI0Ag= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI= +github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea/go.mod h1:eNr558nEUjP8acGw8FFjTeWvSgU1stO7FAO6eknhHe4= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +goa.design/goa v2.0.8+incompatible h1:V6fDjmOsECTcfmVxc1KZlFgUSVp8qd8ojn66sIrSoAo= +goa.design/goa/v3 v3.0.8 h1:icCp0pKZME0KtlaQSt/en8hHmFtwXYM1/AXrFyWmxVs= +goa.design/goa/v3 v3.0.8/go.mod h1:oJR8VOFa4HV7wCQv4XhPtvyknz0B3VFFRUWDdEmI0FI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191030232956-1e24073be82c h1:VBydyJ1aqR8NsGk94ZythzCMGWp9qZKz1mbar2tdih8= +golang.org/x/tools v0.0.0-20191030232956-1e24073be82c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=