Description

I am creating a middleware function, and I want to modify the json that is sent back after the handler function is run. The thing is that, that json could be created in different ways:

c.IndentedJSON(http.StatusOK, body)
c.JSON(http.StatusOK, body)
...

In my middleware function, I would like to modify that json, and return it with the same "rendering" it was created, so, as an example, if it was using the indented json, I want to modify the json e.g, by wrapping it in another json, but return it in indented json format too, as it was originally written in the handler function.

How to reproduce

package main

import (
    "github.com/gin-gonic/gin"
)

func myMiddleware(c *gin.Context) {
   // do something here with the json response
}

func main() {
    g := gin.Default()
        g.Use(myMiddleware)
    g.GET("/hello/:name", func(c *gin.Context) {
                body := map[string]string{"name": "Manuel", "surname":"gin"}
        c.IndentedJSON(200, body)
    })
    g.Run(":9000")
}

Expectations

So in case that the middleware wraps the response, I would expect something like:

$ curl http://localhost:9000/hello/world
{
  "data": {
    "name": "Manuel",
    "surname": "gin"
  }
}

Actual result

$ curl -i http://localhost:9000/hello/world
{"data": {"name":"Manuel","surname": "gin"}}

Because I don't know how it was "rendered", I assumed it was using the normal c.JSON

Environment

  • go version: 1.23
  • gin version (or commit ref):
  • operating system: windows

Comment

Would it make sense to add a key in the context specifying what render was used? Something like:

c.Set("gin:render", "indentedJSON")

Comment From: ChenPuChu

I think your request is not reasonable, because how to return formatted JSON will increase network burden and processing time. And it will make the receiving party more complicated to handle.

Comment From: manuelarte

I think your request is not reasonable, because how to return formatted JSON will increase network burden and processing time. And it will make the receiving party more complicated to handle.

I think I did not explain myself properly, I am making a middleware function, and I want to know what render was used, so I'm not increasing network burden or anything like that.

It's true that in my middleware function I want to change the output, but that's not really related to the question. The question is how can I know what render was used, in case I modify the output, so therefore I can write to the buffer again following the same render

Comment From: ChenPuChu

I think I understand what you mean. You want to customize a json parser and register it in gin. When using c.JSON, your customized parser will be called instead of the default parser. Is my understanding correct?

Comment From: manuelarte

I think I understand what you mean. You want to customize a json parser and register it in gin. When using c.JSON, your customized parser will be called instead of the default parser. Is my understanding correct?

That actually would be a nice feature, but my idea is the following:

func endpointHandler(c *gin.Context) {
...
c.IndentedJSON(200, body)
}

Let's imagine that that endpoint returns the following:

{
  "code": 1,
  "price": 100
}

But now, imagine that I want to create a middleware function, that wraps that output json in a json like this:

{
  "data": {
      "code": 1,
      "price": 100
  },
  "_metadata": {
    "_links": "/products/1"
  }
}

But, if I use a middleware function to modify the output, I am unable to know whether c.JSON, or c.IndentedJSON or what other render, or any other was used to create the original json.

Comment From: ChenPuChu

I think I understand what you mean. You want to customize a json parser and register it in gin. When using c.JSON, your customized parser will be called instead of the default parser. Is my understanding correct?

That actually would be a nice feature, but my idea is the following:

go func endpointHandler(c *gin.Context) { ... c.IndentedJSON(200, body) }

Let's imagine that that endpoint returns the following:

json { "code": 1, "price": 100 }

But now, imagine that I want to create a middleware function, that wraps that output json in a json like this:

json { "data": { "code": 1, "price": 100 }, "_metadata": { "_links": "/products/1" } }

But, if I use a middleware function to modify the output, I am unable to know whether c.JSON, or c.IndentedJSON or what other render, or any other was used to create the original json.

OK, if I understand correctly, the existing gin code cannot meet your requirements, so I want to implement this function during this period. Then I will implement this function according to the ideas I proposed above. If you have better ideas, you are welcome to share them with me.

Comment From: manuelarte

Thanks!

On Fri, Nov 15, 2024, 3:03 PM ChenPuChu @.***> wrote:

I think I understand what you mean. You want to customize a json parser and register it in gin. When using c.JSON, your customized parser will be called instead of the default parser. Is my understanding correct?

That actually would be a nice feature, but my idea is the following:

func endpointHandler(c *gin.Context) {...c.IndentedJSON(200, body) }

Let's imagine that that endpoint returns the following:

{ "code": 1, "price": 100 }

But now, imagine that I want to create a middleware function, that wraps that output json in a json like this:

{ "data": { "code": 1, "price": 100 }, "_metadata": { "_links": "/products/1" } }

But, if I use a middleware function to modify the output, I am unable to know whether c.JSON, or c.IndentedJSON or what other render, or any other was used to create the original json.

OK, if I understand correctly, the existing gin code cannot meet your requirements, so I want to implement this function during this period. Then I will implement this function according to the ideas I proposed above. If you have better ideas, you are welcome to share them with me.

— Reply to this email directly, view it on GitHub https://github.com/gin-gonic/gin/issues/4094#issuecomment-2478918035, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIZ4IYUVUV33EO4JCM3UAD2AX5J5AVCNFSM6AAAAABRZJYFCSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINZYHEYTQMBTGU . You are receiving this because you authored the thread.Message ID: @.***>