I use echo framework in my app and i faced with issue to constuct response from two handler on single entrypoint.
There is example code
type RespObject struct {
Message string `json:"message"`
}
func main() {
e := echo.New()
e.GET("/hello", handler, middle)
e.Logger.Fatal(e.Start(":3000"))
}
func handler(c echo.Context) error {
return c.JSON(http.StatusOK, RespObject{
Message: "Hello",
})
}
func middle(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.JSON(http.StatusOK, RespObject{
Message: "World",
})
return next(c)
}
}
after request i got
curl localhost:3000/hello
{"message":"World"}
{"message":"Hello"}
My goal is make response
{"message":"Hello World"}
echo.Context has struct Response with implement ResponseWriter
But seems ResponseWriter is WriteOnly contract. Is there is a way to some how erase and rebuild data in ResponseWriter?
As far i see there is a two issues
- Read data from ResponseWriter after passing "middle" handler.
- Erase data in ResponseWriter and write new data in "handler" handler
In real issue there is not necessary of name collision of struct. It`s request in two different SCIM API and make combine response.
CodePudding user response:
This can be achieved by creating a custom function that adds the response object and code to context and call it in handler; in middleware you get this object from context, modify the response and call actual c.JSON which writes the modified response to the wire.
const (
echoCtxRespKey = "echo_ctx_resp_key"
)
type RespObject struct {
Message string `json:"message"`
}
type Response struct {
Data interface{}
Code int
}
func main() {
e := echo.New()
e.GET("/hello", handler, middle)
e.Logger.Fatal(e.Start(":3000"))
}
func handler(c echo.Context) error {
resp := RespObject{
Message: "Hello",
}
addResponseToContext(c, Response{
Data: resp,
Code: http.StatusOK,
})
return nil
}
func middle(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
next(c)
resp := getResponseFromContext(c)
// modify resp
return c.JSON(resp.Code, resp.Data)
}
}
func addResponseToContext(c echo.Context, response Response) {
c.Set(echoCtxRespKey, response)
}
func getResponseFromContext(c echo.Context) Response {
return c.Get(echoCtxRespKey).(Response)
}