golang
[gin] JSON
bkdragon
2024. 9. 8. 15:37
gin Context 에 있는 JSON 메서드는 json 응답을 빼주는 데 사용한다. 내부 구현을 살펴보자.
func (c *Context) JSON(code int, obj any) {
c.Render(code, render.JSON{Data: obj})
}
JSON 은 Render라는 메서드를 호출하는데, 상태 코드와 render.JSON을 구조체를 인자로 받는다.
c.Render를 먼저 살펴보면
func (c *Context) Render(code int, r render.Render) {
c.Status(code)
if !bodyAllowedForStatus(code) {
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
return
}
if err := r.Render(c.Writer); err != nil {
// Pushing error to c.Errors
_ = c.Error(err)
c.Abort()
}
}
눈치가 빠르다면 메서드의 시그니처를 보고 Render 는 인터페이스이고 JSON 구조체가 Render의 구현체이라는 것을 알 수 있다.
팩트일지 체크해보자.
type Render interface {
// Render writes data with custom ContentType.
Render(http.ResponseWriter) error
// WriteContentType writes custom ContentType.
WriteContentType(w http.ResponseWriter)
}
우선 인터페이스는 맞다. Render, WriteContentType 메서드를 가지고 있다.
type JSON struct {
Data any
}
JSON 은 우선 데이터라는 속성을 가지고 있고,
// Render (JSON) writes data with custom ContentType.
func (r JSON) Render(w http.ResponseWriter) error {
return WriteJSON(w, r.Data)
}
// WriteContentType (JSON) writes JSON ContentType.
func (r JSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType)
}
이렇게 Render, WriteContentType 메서드를 가지고 있다. 눈치게임 성공이다.
WriteJson에 응답을 쓰는 코드가 작성되어있을 것이다.
func WriteJSON(w http.ResponseWriter, obj any) error {
writeContentType(w, jsonContentType)
jsonBytes, err := json.Marshal(obj)
if err != nil {
return err
}
_, err = w.Write(jsonBytes)
return err
}
Marshal 하고 Write 하는 걸 확인할 수 있다.
근데 ShouldBindJSON 메서드와는 다르게 스트림 방식을 사용하진 않는다.
스트림 방식으로 변경을 한번 해보자.
func WriteJSON(w http.ResponseWriter, obj any) error {
writeContentType(w, jsonContentType)
encoder := json.NewEncoder(w)
return encoder.Encode(obj)
}
good!