Is there a way to set a custom JSON serializer?
Sometimes, I need to communicate with other services, especially legacy ones. I require all keys in the JSON response to be formatted in snake_case, lower case, or upper case. Is there a way to achieve this? e.g.
gin.SetJson(&customeJsonSerializer{})
// or
r := gin.Default()
r.SetJson(&customeJsonSerializer{})
Comment From: takanuva15
Hey I was wondering the same exact thing since I was trying to serialize all my time.Time
fields as unix millisecond integers rather than string dates. There is an open PR #3391 which would enable us to fully customize the Marshal/Unmarshal methods that gin uses for json conversion. It might get merged and released for gin v1.11, but that's not definitive.
In the meantime though, gin has a render.Render
interface that you can manipulate to serialize the json any way you like.
First, define your custom render function. In my case, I wanted to use the new experimental json/v2 package for marshalling so I could take advantage of their new json options like omitzero
and format:unixmilli
:
// this code is a copy-paste of the existing render.JSON struct except for the json package being used for marshalling
import (
"net/http"
"github.com/gin-gonic/gin/render"
"github.com/go-json-experiment/json/v1"
)
type JSONv2 struct {
render.JSON
}
func (r JSONv2) Render(w http.ResponseWriter) error {
writeContentType(w, []string{"application/json; charset=utf-8"})
jsonBytes, err := json.Marshal(r.Data)
if err != nil {
return err
}
_, err = w.Write(jsonBytes)
return err
}
func writeContentType(w http.ResponseWriter, value []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = value
}
}
I also added a utility method to make the JSONv2 struct easier to use in my gin endpoints:
func WithJSONv2(data any) JSONv2 {
return JSONv2{render.JSON{Data: data}}
}
Then in your gin code, you just need to invoke the function like so:
c.Render(200, WithJSONv2(res))
And that's it!
Note that this is not as elegant as the open PR since you will need to invoke WithJSONv2 in every endpoint where you want to use your custom serializer. But hopefully whenever the PR gets merged, you can run a quick regex replace on your codebase to convert all these usages back to the normal c.JSON(200, res)
that's standard.
Comment From: Scythemen
Thank you