From 574aa271c80663db26251753bc47d1fddce56d25 Mon Sep 17 00:00:00 2001 From: 54m <30588003+54m@users.noreply.github.com> Date: Sun, 3 May 2026 12:42:51 +0900 Subject: [PATCH 1/2] fix(deps): bump go-easyparser to v0.5.0 for *types.Alias support Go 1.23 makes gotypesalias=1 the default, causing type aliases such as any (alias for interface{}) to appear as *types.Alias in go/types. go-easyparser v0.5.0 handles *types.Alias, *types.Signature, and *types.TypeParam, fixing the panic in api_gen. - go.mod - go.sum --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 2423fcd..79530e8 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/spf13/cobra v1.8.0 golang.org/x/sync v0.20.0 golang.org/x/tools v0.44.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 + golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 ) require ( github.com/fatih/structtag v1.2.0 github.com/go-generalize/go-dartfmt v0.1.1 - github.com/go-generalize/go-easyparser v0.3.3 + github.com/go-generalize/go-easyparser v0.5.0 github.com/go-generalize/go2dart v0.5.1 ) diff --git a/go.sum b/go.sum index 5da3fbf..aa5baac 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4 github.com/go-generalize/go-dartfmt v0.1.1 h1:2W+CD7qGCNE/0JLtm394RJBBi/jhtXUcJ+G0v0Bcx88= github.com/go-generalize/go-dartfmt v0.1.1/go.mod h1:xbPNNnCJpX/CtvxIy1grvi9X2A57jC6fsvoYVDXpAWQ= github.com/go-generalize/go-easyparser v0.2.0/go.mod h1:I+Ifnjzw7UNzxkENknQQY9yB2gsz9RekzAbKLYq/Dzw= -github.com/go-generalize/go-easyparser v0.3.3 h1:sX1y6pON1dWEjVIzQr1FHRboM/4LRdXmTJHQf/h4caM= -github.com/go-generalize/go-easyparser v0.3.3/go.mod h1:8Rs26IvI49PII6hWsIRw02/rJrzBrxSrkDgY+Wbt+2E= +github.com/go-generalize/go-easyparser v0.5.0 h1:MyNXGpesbbXMZbITWATrRl/+UU5NwUMOctfx4oYeMWk= +github.com/go-generalize/go-easyparser v0.5.0/go.mod h1:JY2y+clYM+/gEN3AdoZrHjqk0TvpOrE7KOSK+cwu1VQ= github.com/go-generalize/go2dart v0.5.1 h1:eeSjP7GMArcPHZ+sMYQxU79MxjHDqaQvLcNHdV0erFI= github.com/go-generalize/go2dart v0.5.1/go.mod h1:peqHvoBnlWmpJPoYaIyGBditWFaNZ6jR0ywbIRNdY8o= github.com/go-generalize/go2go v0.2.1 h1:YLUiBx8W9WgSeYDJnuF79Hx0dkMZu1VZygeyasCbyvk= @@ -97,8 +97,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= 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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 4e5989b990c5df6243835fe2b0f2446befbe58a6 Mon Sep 17 00:00:00 2001 From: 54m <30588003+54m@users.noreply.github.com> Date: Sun, 3 May 2026 12:46:01 +0900 Subject: [PATCH 2/2] test(parser): add regression test for *types.Alias via map[string]any Adds a minimal reproduction case under pkg/server/testdir/alias_repro/ that exercises map[string]any (which triggers *types.Alias in Go 1.23+). The generated server/ directory is committed as a static fixture so the regression is detected if go-easyparser ever drops the *types.Alias case again. This testdir is intentionally NOT added to make gen_samples to avoid false-positive diffs from version-string drift. - pkg/server/server_test.go - pkg/server/testdir/alias_repro/interfaces/get.go - pkg/server/testdir/alias_repro/server/ --- pkg/server/server_test.go | 30 ++++ .../testdir/alias_repro/interfaces/get.go | 14 ++ .../testdir/alias_repro/server/bundler.go | 71 ++++++++ .../alias_repro/server/controller/get.go | 47 +++++ .../server/controller_initializer.go | 91 ++++++++++ .../alias_repro/server/mock/controller/get.go | 168 ++++++++++++++++++ .../server/mock/json/get/default.json | 15 ++ .../testdir/alias_repro/server/mock/mock.go | 19 ++ .../alias_repro/server/mock_bundler.go | 71 ++++++++ .../server/pkg/apierror/apierror.go | 56 ++++++ .../testdir/alias_repro/server/props/props.go | 7 + 11 files changed, 589 insertions(+) create mode 100644 pkg/server/testdir/alias_repro/interfaces/get.go create mode 100644 pkg/server/testdir/alias_repro/server/bundler.go create mode 100644 pkg/server/testdir/alias_repro/server/controller/get.go create mode 100644 pkg/server/testdir/alias_repro/server/controller_initializer.go create mode 100644 pkg/server/testdir/alias_repro/server/mock/controller/get.go create mode 100644 pkg/server/testdir/alias_repro/server/mock/json/get/default.json create mode 100644 pkg/server/testdir/alias_repro/server/mock/mock.go create mode 100644 pkg/server/testdir/alias_repro/server/mock_bundler.go create mode 100644 pkg/server/testdir/alias_repro/server/pkg/apierror/apierror.go create mode 100644 pkg/server/testdir/alias_repro/server/props/props.go diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index eef202f..fb7e1b6 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -27,3 +27,33 @@ func TestGenerate(t *testing.T) { t.Fatal(err) } } + +// TestGenerateAliasRepro is a regression test for *types.Alias support (Go 1.23+). +// With GODEBUG=gotypesalias=1 (the default since Go 1.23), type aliases such as +// "any" (alias for interface{}) appear as *types.Alias in go/types output. +// go-easyparser v0.3.3 (used in api_gen v2.14.1) lacked a case for *types.Alias and +// panicked with "unsupported named type: *types.Alias" for any interface that uses +// map[string]any. This test verifies that code generation completes without error. +// The static fixture under testdir/alias_repro/server/ is intentionally NOT +// added to make gen_samples to avoid false-positive diffs from version-string drift. +func TestGenerateAliasRepro(t *testing.T) { + gr, err := parser.Parse("./testdir/alias_repro/interfaces") + + if err != nil { + t.Fatalf("parser.Parse failed (regression: *types.Alias support): %v", err) + } + + // Use a subdirectory under testdir so gopackages.NewModule can find testdir/go.mod. + outDir := "./testdir/alias_repro/server" + _ = os.RemoveAll(outDir) + + gen, err := NewGenerator(gr, outDir, "server", "devel") + + if err != nil { + t.Fatalf("NewGenerator failed: %v", err) + } + + if err := gen.Generate(); err != nil { + t.Fatalf("Generate failed (regression: *types.Alias support): %v", err) + } +} diff --git a/pkg/server/testdir/alias_repro/interfaces/get.go b/pkg/server/testdir/alias_repro/interfaces/get.go new file mode 100644 index 0000000..367e943 --- /dev/null +++ b/pkg/server/testdir/alias_repro/interfaces/get.go @@ -0,0 +1,14 @@ +// Package interfaces contains request/response types for alias_repro regression test. +// This file intentionally uses map[string]any which triggers *types.Alias in Go 1.23+ +// with GODEBUG=gotypesalias=1 (the default since Go 1.23). +package interfaces + +// GetRequest - request type with map[string]any (triggers *types.Alias in Go 1.23+) +type GetRequest struct { + Extra map[string]any `json:"extra"` +} + +// GetResponse - response type with map[string]any +type GetResponse struct { + Data map[string]any `json:"data"` +} diff --git a/pkg/server/testdir/alias_repro/server/bundler.go b/pkg/server/testdir/alias_repro/server/bundler.go new file mode 100644 index 0000000..f47852f --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/bundler.go @@ -0,0 +1,71 @@ +//go:build !mock +// +build !mock + +// Code generated by api_gen. DO NOT EDIT. +// generated version: devel +package server + +import ( + "net/http" + + types_interfaces_21ff36cc "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/interfaces" + ctrl_controller_b7c4244f "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/controller" + apierror "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/pkg/apierror" + props "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/props" + echo "github.com/labstack/echo/v4" + xerrors "golang.org/x/xerrors" +) + +func addRoutes(e *echo.Echo, p *props.ControllerProps, opt *options) { + add := func(method, path string, handler func(c echo.Context) (interface{}, error)) { + e.Add(method, path, func(c echo.Context) error { + var werr *apierror.APIError + + res, err := handler(c) + + if err != nil { + if !opt.disableErrorHandling && xerrors.As(err, &werr) { + c.Logger().Errorf("%+v", werr) + return c.JSON(werr.Status, werr.Body) + } + return xerrors.Errorf("%s %s returned an error: %w", method, path, err) + } + if res == nil { + return nil + } + + return c.JSON(http.StatusOK, res) + }) + } + + { + ctrl := ctrl_controller_b7c4244f.NewGetController(p) + + add("GET", "/", func(c echo.Context) (interface{}, error) { + req := new(types_interfaces_21ff36cc.GetRequest) + if err := c.Bind(req); err != nil { + c.Logger().Errorf("failed to bind a request for (/): %+v", err) + return nil, c.JSON(http.StatusBadRequest, map[string]interface{}{ + "code": http.StatusBadRequest, + "message": "invalid request.", + }) + } + if err := c.Validate(req); err != nil && err != echo.ErrValidatorNotRegistered { + return nil, xerrors.Errorf("the validator returned an error: %w", err) + } + + res, err := ctrl.Get(c, req) + + if err != nil { + return nil, xerrors.Errorf("the handler(Get) returned an error: %w", err) + } + + if res == nil { + return nil, nil + } + + return res, nil + }) + } + +} diff --git a/pkg/server/testdir/alias_repro/server/controller/get.go b/pkg/server/testdir/alias_repro/server/controller/get.go new file mode 100644 index 0000000..a33ceeb --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/controller/get.go @@ -0,0 +1,47 @@ +// Package controller handles requests and returns responses. api_gen users directly edit this file. +// generated version: devel +// nolint:dupl +package controller + +import ( + types "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/interfaces" + props "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/props" + "github.com/labstack/echo/v4" +) + +// GetController ... +type GetController interface { + Get(c echo.Context, req *types.GetRequest) (res *types.GetResponse, err error) +} + +type getController struct { + *props.ControllerProps +} + +// NewGetController ... +func NewGetController(cp *props.ControllerProps) GetController { + return &getController{ + ControllerProps: cp, + } +} + +// Get - GET +func (ctrl *getController) Get( + c echo.Context, req *types.GetRequest, +) (res *types.GetResponse, err error) { + // return nil, apierror.NewAPIError(http.StatusBadRequest) + // + // return nil, apierror.NewAPIError(http.StatusBadRequest).SetError(err) + // + // body := map[string]interface{}{ + // "code": http.StatusBadRequest, + // "message": "invalid request parameter.", + // } + // return nil, apierror.NewAPIError(http.StatusBadRequest, body).SetError(err) + panic("require implements.") // FIXME require implements. +} + +// AutoBind - use echo.Bind +func (ctrl *getController) AutoBind() bool { + return true +} diff --git a/pkg/server/testdir/alias_repro/server/controller_initializer.go b/pkg/server/testdir/alias_repro/server/controller_initializer.go new file mode 100644 index 0000000..8bda82c --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/controller_initializer.go @@ -0,0 +1,91 @@ +// Code generated by api_gen. DO NOT EDIT. +// Package controller binds handlers to echo +// generated version: devel +package server + +import ( + "net/http" + "runtime/debug" + "strings" + + apierror "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/pkg/apierror" + props "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/props" + "github.com/go-utils/echo-multipart-binder/mjbinder" + "github.com/go-utils/echo-multipart-binder/mpbinder" + "github.com/labstack/echo/v4" +) + +type middleware struct { + path string + middleware echo.MiddlewareFunc +} + +type options struct { + disableErrorHandling bool +} + +// Controllers binds handlers to echo +type Controllers struct { + middlewares []middleware + options +} + +// NewControllers returns a new Controllers +func NewControllers( + props *props.ControllerProps, e *echo.Echo, +) *Controllers { + ctrl := &Controllers{} + + e.Binder = mjbinder.NewMultipartJSONBinder(mpbinder.NewMultipartFileBinder(e.Binder)) + e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + for _, m := range ctrl.middlewares { + if strings.HasPrefix(c.Request().URL.Path, m.path) { + next = m.middleware(next) + } + } + + return next(c) + } + }) + e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) (err error) { + defer func() { + recoverErr := recover() + if recoverErr == nil { + return + } + + c.Logger().Errorf("process panic: %#v\n", recoverErr) + debug.PrintStack() + + if httpErr, ok := recoverErr.(*echo.HTTPError); ok { + err = c.JSON(httpErr.Code, httpErr.Message) + + return + } + + err = apierror.NewAPIError(http.StatusInternalServerError, "internal server error.") + }() + + return next(c) + } + }) + + addRoutes(e, props, &ctrl.options) + + return ctrl +} + +// AddMiddleware adds 'm' to the paths starting with the 'path'. +func (c *Controllers) AddMiddleware(path string, m echo.MiddlewareFunc) { + c.middlewares = append(c.middlewares, middleware{ + path: path, + middleware: m, + }) +} + +// DisableErrorHandling disables +func (c *Controllers) DisableErrorHandling() { + c.disableErrorHandling = true +} diff --git a/pkg/server/testdir/alias_repro/server/mock/controller/get.go b/pkg/server/testdir/alias_repro/server/mock/controller/get.go new file mode 100644 index 0000000..029e742 --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/mock/controller/get.go @@ -0,0 +1,168 @@ +// Code generated by api_gen. DO NOT EDIT. +// generated version: devel +// nolint:dupl +package controller + +import ( + "encoding/json" + "fmt" + "io/fs" + "log" + "net/http" + "reflect" + "sort" + "strings" + "time" + + types "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/interfaces" + mock "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/mock" + "github.com/labstack/echo/v4" +) + +// GetController ... +type GetController interface { + Get(c echo.Context, req *types.GetRequest) (res *types.GetResponse, err error) +} + +type getController struct { +} + +// NewGetController ... +func NewGetController(cp interface{}) GetController { + return &getController{} +} + +// Get - GET +// @Accept json +// @Produce json +// @Param extra query interface{} true "extra" +// @Success 200 {object} types.GetResponse +// @Router / [get] +func (ctrl *getController) Get( + c echo.Context, req *types.GetRequest, +) (res *types.GetResponse, err error) { + const jsonExt = ".json" + + option := &mock.HeaderOption{} + ago := c.Request().Header.Get("Api-Gen-Option") + if ago != "" { + if err := json.Unmarshal([]byte(ago), option); err != nil { + log.Printf("failed to JSON Unmarshal to `Api-Gen-Option` header(/): %+v", err) + return nil, c.JSON(http.StatusBadRequest, map[string]interface{}{ + "code": http.StatusBadRequest, + "message": "invalid Api-Gen-Option.", + }) + } + } + + if option.UseMatchRequest == nil { + flag := true + option.UseMatchRequest = &flag + } + + if option.WaitMS > 0 { + <-time.After(time.Duration(option.WaitMS) * time.Millisecond) + } + + type Mock struct { + Meta struct { + Status int `json:"status"` + MatchRequest *types.GetRequest `json:"match_request"` + } `json:"meta"` + Payload interface{} `json:"payload"` + } + + jsons := make(map[string]*Mock) + err = fs.WalkDir(mock.MockJSONFS, "json/get_", fs.WalkDirFunc(func(path string, info fs.DirEntry, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + fp, err := mock.MockJSONFS.Open(path) + if err != nil { + log.Printf("SKIP: load mock json error in %s: %+v", path, err) + return nil + } + defer fp.Close() + + mock := new(Mock) + + err = json.NewDecoder(fp).Decode(mock) + if err != nil { + log.Printf("SKIP: unmarshal mock json error in %s: %+v", path, err) + return nil + } + + jsons[info.Name()] = mock + log.Printf("load %s", path) + + return nil + })) + + if err != nil { + m := fmt.Sprintf("jsons load error: %+v", err) + log.Println(m) + return nil, c.JSON(http.StatusInternalServerError, map[string]interface{}{ + "code": http.StatusInternalServerError, + "message": m, + }) + } + + var resMock *Mock = nil + if option.TargetFile != "" { + target := option.TargetFile + if !strings.HasSuffix(target, jsonExt) { + target += jsonExt + } + mock, ok := jsons[target] + if ok { + resMock = mock + } + } else if *option.UseMatchRequest { + jsonNameList := make([]string, 0, len(jsons)) + for key := range jsons { + jsonNameList = append(jsonNameList, key) + } + sort.Strings(jsonNameList) + + for _, jsonName := range jsonNameList { + m := jsons[jsonName] + if !reflect.DeepEqual(m.Meta.MatchRequest, req) { + continue + } + resMock = jsons[jsonName] + log.Printf("[%s] Return the %s because it matches a rule.", jsonName, jsonName) + break + } + } + if resMock == nil { + mock, ok := jsons["default.json"] + if !ok { + m := fmt.Sprintf("not match request and not found default.json") + log.Println(m) + return nil, c.JSON(http.StatusInternalServerError, map[string]interface{}{ + "code": http.StatusInternalServerError, + "message": m, + }) + } + + if *option.UseMatchRequest { + log.Println("[default.json] Return the default.json because it did not match rule.") + } else { + log.Println("[default.json] Return the default.json because use_match_request is disabled.") + } + + resMock = mock + } + + return nil, c.JSON(resMock.Meta.Status, resMock.Payload) +} + +// AutoBind - use echo.Bind +func (ctrl *getController) AutoBind() bool { + return true +} diff --git a/pkg/server/testdir/alias_repro/server/mock/json/get/default.json b/pkg/server/testdir/alias_repro/server/mock/json/get/default.json new file mode 100644 index 0000000..d21850f --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/mock/json/get/default.json @@ -0,0 +1,15 @@ +{ + "meta": { + "status": 200, + "match_request": { + "extra": { + "string": "any" + } + } + }, + "payload": { + "data": { + "string": "any" + } + } +} diff --git a/pkg/server/testdir/alias_repro/server/mock/mock.go b/pkg/server/testdir/alias_repro/server/mock/mock.go new file mode 100644 index 0000000..dbdf273 --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/mock/mock.go @@ -0,0 +1,19 @@ +// Code generated by api_gen. DO NOT EDIT. +// generated version: devel +package mock + +import ( + "embed" +) + +// MockJSONFS provides embed.FS for mock json +// +//go:embed json/* +var MockJSONFS embed.FS + +// HeaderOption is the header of Api-Gen-Option in JSON +type HeaderOption struct { + WaitMS int64 `json:"wait_ms"` + TargetFile string `json:"target_file"` + UseMatchRequest *bool `json:"use_match_request"` +} diff --git a/pkg/server/testdir/alias_repro/server/mock_bundler.go b/pkg/server/testdir/alias_repro/server/mock_bundler.go new file mode 100644 index 0000000..f75ff33 --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/mock_bundler.go @@ -0,0 +1,71 @@ +//go:build mock +// +build mock + +// Code generated by api_gen. DO NOT EDIT. +// generated version: devel +package server + +import ( + "net/http" + + types_interfaces_21ff36cc "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/interfaces" + ctrl_controller_0da40676 "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/mock/controller" + apierror "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/pkg/apierror" + props "github.com/go-generalize/api_gen/v2/pkg/server/tmp/alias_repro/server/props" + echo "github.com/labstack/echo/v4" + xerrors "golang.org/x/xerrors" +) + +func addRoutes(e *echo.Echo, p *props.ControllerProps, opt *options) { + add := func(method, path string, handler func(c echo.Context) (interface{}, error)) { + e.Add(method, path, func(c echo.Context) error { + var werr *apierror.APIError + + res, err := handler(c) + + if err != nil { + if !opt.disableErrorHandling && xerrors.As(err, &werr) { + c.Logger().Errorf("%+v", werr) + return c.JSON(werr.Status, werr.Body) + } + return xerrors.Errorf("%s %s returned an error: %w", method, path, err) + } + if res == nil { + return nil + } + + return c.JSON(http.StatusOK, res) + }) + } + + { + ctrl := ctrl_controller_0da40676.NewGetController(p) + + add("GET", "/", func(c echo.Context) (interface{}, error) { + req := new(types_interfaces_21ff36cc.GetRequest) + if err := c.Bind(req); err != nil { + c.Logger().Errorf("failed to bind a request for (/): %+v", err) + return nil, c.JSON(http.StatusBadRequest, map[string]interface{}{ + "code": http.StatusBadRequest, + "message": "invalid request.", + }) + } + if err := c.Validate(req); err != nil && err != echo.ErrValidatorNotRegistered { + return nil, xerrors.Errorf("the validator returned an error: %w", err) + } + + res, err := ctrl.Get(c, req) + + if err != nil { + return nil, xerrors.Errorf("the handler(Get) returned an error: %w", err) + } + + if res == nil { + return nil, nil + } + + return res, nil + }) + } + +} diff --git a/pkg/server/testdir/alias_repro/server/pkg/apierror/apierror.go b/pkg/server/testdir/alias_repro/server/pkg/apierror/apierror.go new file mode 100644 index 0000000..734d5e7 --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/pkg/apierror/apierror.go @@ -0,0 +1,56 @@ +// Code generated by api_gen. DO NOT EDIT. +// generated version: devel +package apierror + +import ( + "fmt" + "net/http" + + "golang.org/x/xerrors" +) + +// APIError - API Error +type APIError struct { + Status int `json:"status"` + Body interface{} `json:"body"` + err error `json:"-"` +} + +// NewAPIError - constructor +func NewAPIError(status int, bodies ...interface{}) *APIError { + ae := &APIError{Status: status} + + switch len(bodies) { + case 0: + ae.Body = map[string]interface{}{ + "code": status, + "message": http.StatusText(status), + } + case 1: + ae.Body = bodies[0] + default: + ae.Body = bodies + } + + return ae +} + +// Error - makes it compatible with `error` interface. +func (ae *APIError) Error() string { + if ae.err == nil { + return fmt.Sprintf("status=%d, body=%v", ae.Status, ae.Body) + } + return fmt.Sprintf("status=%d, body=%v, err=%+v", ae.Status, ae.Body, ae.err) +} + +// SetError - sets error to APIError.err +func (ae *APIError) SetError(err error) *APIError { + ae.err = xerrors.Errorf(": %w", err) + return ae +} + +// SetErrorf - sets error to APIError.err (use `%w` to wrap the error) +func (ae *APIError) SetErrorf(format string, a ...interface{}) *APIError { + ae.err = xerrors.Errorf(format, a...) + return ae +} diff --git a/pkg/server/testdir/alias_repro/server/props/props.go b/pkg/server/testdir/alias_repro/server/props/props.go new file mode 100644 index 0000000..0033b09 --- /dev/null +++ b/pkg/server/testdir/alias_repro/server/props/props.go @@ -0,0 +1,7 @@ +// Package props is a scaffold file for props of controllers +package props + +// ControllerProps is passed from Bootstrap() to all controllers +type ControllerProps struct { + // DB, config, etc... +}