Backend with Golang

Go: JSON

아직개구리 2023. 5. 3. 01:44

https://gobyexample.com/json 

 

Go by Example: JSON

$ go run json.go true 1 2.34 "gopher" ["apple","peach","pear"] {"apple":5,"lettuce":7} {"Page":1,"Fruits":["apple","peach","pear"]} {"page":1,"fruits":["apple","peach","pear"]} map[num:6.13 strs:[a b]] 6.13 a {1 [apple peach]} apple {"apple":5,"lettuce":7}

gobyexample.com

JSON encoding, decoding을 위해서 built-in support를 제공한다.

 

Marshal: golang object를 []byte나 string으로 변환 

Unmarshal: []byte, string -> golang object로 변환하는 과정 

 

https://go.dev/blog/json 

 

JSON and Go - The Go Programming Language

JSON and Go Andrew Gerrand 25 January 2011 Introduction JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is most commonly used for communication between web back-ends

go.dev

1. Encoding

func Marshal(v interface{}) ([]byte, error)

2. Decoding: decoded data 가 들어갈 공간을 create 해야한다. data가 v에 들어갈 valid JSON 이라면, err = nil이다. 

func Unmarshal(data []byte, v interface{}) error

unmarshal을 할때 JSON에 key가  Foo라면, struct 의 field에서 destination을 찾는데 아래와 같은 순서로 이루어진다. 

  • An exported field with a tag of "Foo"
  • An exported field named "Foo", or
  • An exported field named "FOO" or "FoO" or some other case-insensitive match of "Foo".

해당하는 field가 없으면 ignored 된다. 

 

 

JSON data structure 를 모를때는 ? 

The empty interface serves as a general container type 

The json package uses map[string]interface{} and []interface{} values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plain interface{} value. The default concrete Go types are:

  • bool for JSON booleans,
  • float64 for JSON numbers,
  • string for JSON strings, and
  • nil for JSON null. 

더불어 Type switch 를 사용하면 모르는 타입에 대해서도 안전하게 사용할 수 있다. 

 

Reference Types

type FamilyMember struct {
    Name    string
    Age     int
    Parents []string
}

var m FamilyMember
err := json.Unmarshal(b, &m)

 이런 코드를 생각해 보자. 이때 먼저 var statement부분과 json.Unmarshal로 두개의 단계로 나뉘어지게 된다.

1. var m FamilyMemeber: 이 부분에서는 Parents는 nil slice value이다. 

2. Unmarshal 에서는 Parents field를 polulate하기 위해서 새로운 slice를 allocate 시킨다. 

 

만약에 이제 아래와 같은 data type인데, JSON object에 Cmd가 없으면 Cmd는 nil pointer이고, Msg도 마찬가지이다. 어떤 message가 처리되어야 하는지 알기 위해서는 Cmd나 Msg가 nil인지 확인하면 되는 것이다. 

type IncomingMessage struct {
    Cmd *Command
    Msg *Message
}

 만약에 struct내부에 pointer가 아닌 int같은 것이 있었으면, 0 으로 초기화 될 것이다. 

 

Omitempty tag (+ json tag)

reference: https://pkg.go.dev/encoding/json 

 

각 struct의 field를 encoding할때, struct field's tag에 json이라는 key아래에 저장된 format string에 의해 customized될 수 있다. 

이 format string은 name of the field를 제공하고, 그 뒤에 comma로 분리될 수 있는 옵션 리스트가 따라 붙는다. 

omitempty option은 encoding 될 때 field가 empty value라면 omit할 것이라는 것을 나타내는 옵션이다. 여기서 empty value에는  false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string 등이 포함된다. special case로는, tag가 "-"일때는  field 자체가 항상 omitted되는 것이다. 주의할 점은 "-,"일 때, field 이름이 -로 나타날 수 있음을 주의하자. 

 

예시로 든 것들을 보면, 아래와 같다. 

// JSON에 myName이라는 key로 나타난다. 
Field int `json:"myName"`

// JSON에 myName이라는 key로 나타나고,empty value이면 나타나지 않고 omitted. 
Field int `json:"myName,omitempty"`

// 이렇게 쉼표가 바로 나오면, struct의 key가 그대로 적용되어 "Field"라는 키를 가지게 된다. 
// 마찬가지로 empty value이면 omitted된다. 
Field int `json:",omitempty"`

// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "-".
Field int `json:"-,"`

여기서 구조체 field를 숨기고 싶다면?

empty value에서 nil pointer를 사용하면 되는 것이다. 구조체 필드를 구조체 포인터 필드로 바꿔서 사용하면 된다. 

일반 구조체 필드를 사용하면, struct를 만들어서 보내주기 때문에 {}가 value로 들어있고, 구조체 포인터로 된 필드를 사용하게 되면, omitempty가 적용된다. 

결과적으로 필드의 자료형이 struct라면, omitempty tag에 영향을 받아서 데이터가 없을 때 필드 자체가 출력되지 않도록 하기 위해서는 필드의 자료형을 구조체 포인터로 선언하면 된다는 것이다. 

 

남은 질문 

concrete type이란?? 

'Backend with Golang' 카테고리의 다른 글

MySQL - Transaction  (0) 2023.05.09
Docker-compose.yml 파일 작성하기 (TBU)  (0) 2023.05.09
Goroutine  (0) 2023.05.01
Go's Syntax  (0) 2023.04.27
Docker 기본 개념  (1) 2023.04.26