kataras / iris

The fastest HTTP/2 Go Web Framework. New, modern and easy to learn. Fast development with Code you control. Unbeatable cost-performance ratio :rocket:
https://www.iris-go.com
BSD 3-Clause "New" or "Revised" License
25.11k stars 2.48k forks source link

[BUG]`hero.Resulthandler` can only handle custom struct #2448

Open dydhyhwu opened 4 months ago

dydhyhwu commented 4 months ago

hero.ResultHandler can only handle cases where the return value is a custom struct or dispatcher. After reviewing the code, I found that before ResultHandler processing, it needs to go through dispatchFuncResult processing, and then dispatchCommon decides whether to call handlers. I would like to know why it was designed this way.

In scenarios where Container is used to uniformly handle return values, I hope that the return values of all Handlers are uniformly wrapped and processed, so that a unified return value structure can be obtained. However, the framework has specialized handling for some basic types, which forces me to call ctx.JSON(map[string]interface{} {...}) in some handlers.

The code and expected result I hope to achieve is as follows:

type Response struct {
    Code int         `json:"code"`
    Data interface{} `json:"data,omitempty"`
    Msg  string      `json:"msg,omitempty"`
}

type testOutput struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

func resultFormatter(next hero.ResultHandler) hero.ResultHandler {
    return func(ctx iris.Context, v interface{}) error {
        log.Infof("use result handler\n")

        return next(ctx, map[string]interface{}{
            "code": 200,
            "data": v,
            "msg":  "",
        })
    }
}

func emptyResHandler(ctx iris.Context) {
    log.Info("hello")
}

func boolResHandler(ctx iris.Context) bool {
    return true
}

func stringResHandler(ctx iris.Context) string {
    return "hello"
}

func intResHandler(ctx iris.Context) int {
    return 1
}

func int64ResHandler(ctx iris.Context) int64 {
    return 1
}

func structResHandler(ctx iris.Context) testOutput {
    return testOutput{
        ID:   1,
        Name: "hello",
    }
}

func configureApi(api *iris.APIContainer) {
    api.UseResultHandler(resultFormatter)
    api.Get("/empty", emptyResHandler)
    api.Get("/bool", boolResHandler)
    api.Get("/string", stringResHandler)
    api.Get("/int", intResHandler)
    api.Get("/int64", int64ResHandler)
    api.Get("/struct", structResHandler)
}

when the return value is empty, the expected result is:

{
    "code": 200,
    "data": null,
    "msg": ""
}

when the return value is string, the expected result is:

{
    "code": 200,
    "data": "string",
    "msg": ""
}

when the return value is custom struct, the expected result is :

{
    "code": 200,
    "data": {
        "id": 1,
        "name": "test"
    },
    "msg": ""
}

and so on...

dydhyhwu commented 4 months ago

related code: https://github.com/kataras/iris/blob/b904793278a3241da109503f127cdb8aed8e9e34/hero/func_result.go#L264-L331

https://github.com/kataras/iris/blob/b904793278a3241da109503f127cdb8aed8e9e34/hero/func_result.go#L366-L373

dydhyhwu commented 4 months ago

@kataras need some help