Go에서는 json 패키지 이용해서 JSON 데이터를 읽고 쓸 수 있다. 오늘은 Go 구조체와 json 패키지를 이용해 JSON 데이터를 읽고 쓰는 방법에 대하여 정리하겠다. 먼저 Go의 json 패키지에 있는 두 함수에 대하여 알아보자.
마샬링과 언마샬링
마샬링
Go 자료형을 JSON 데이터로 변경합니다. Marshal 함수를 사용한다.
func Marshal(v interface{}) ([]byte, error)
언마샬링
마샬링과 반대로 JSON 데이터를 Go 자료형으로 변환합니다. Unmarshal 함수를 이용한다.
func Unmarshal(data []byte, v interface{}) error
이제부터 예제를 통해 Go에서 JSON 다루는 방법에 대하여 알아보자.
Simple JSON
우선 간단한 JSON 다루는 방법이다.
type Movie struct {
Id int
Title string
Adult bool
Year int
}
func main() {
m := Movie{1, "The Dark Knight", false, 2008}
b, err := json.Marshal(m)
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Println(string(b))
}
실행 결과는 다음과 같다.
{
"Id": 1,
"Title": "The Dark Knight",
"Adult": false,
"Year": 2008
}
마샬링 되는 결과의 JSON 필드의 key 이름을 변경할 수 있다.
구조체 필드 선언에 태그(json:"이름"
)를 사용하면 된다.
type Movie struct {
Id int `json:"id"`
Title string `json:"title"`
Adult bool `json:"adult"`
Year int `json:"released"`
}
실행 결과는 다음과 같다. 설정한 이름들로 나오는 것을 확인할 수 있다.
{
"id": 1,
"title": "The Dark Knight",
"adult": false,
"released": 2008
}
필드에 값이 없을 경우 마샬링되는 결과에 포함시키지 않을 수도 있다.
omitempty 옵션을 추가하여 해당 필드를 JSON data로 변환하지 않다. omitempty 옵션을 사용하면 false, 0, a nil pointer, a nil interface value, 그리고 비어있는 array, slice, map, string는 변환되지 않는다.
type Movie struct {
Id int `json:"id"`
Title string `json:"title"`
Adult bool `json:"adult,omitempty"`
Year int `json:"released"`
}
func main() {
m := Movie{1, "The Dark Knight", false, 2008}
b, err := json.Marshal(m)
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Println(string(b))
}
실행 결과는 다음과 같다. adult 필드가 false이기 때문에 무시되어 나온다.
{
"id": 1,
"title": "The Dark Knight",
"released": 2008
}
Unmarshal를 이용해서 JSON 데이터를 Go의 값으로 변환할 수 있다.
func main() {
data := []byte(`
{
"id": 1,
"title": "The Dark Knight",
"adult": false,
"released": 2008
}
`)
var movie Movie
err := json.Unmarshal(data, &movie)
if err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
os.Exit(1)
}
fmt.Printf("%+v\n", movie)
}
실행 결과는 다음과 같다.
{Id:1 Title:The Dark Knight Adult:false Year:2008}
Array JSON
Array JSON 마샬링 하는 것을 해보자.
func main() {
m := []Movie{
{1, "The Dark Knight", false, 2008},
{2, "The Godfather", true, 1972},
{3, "GoodFellas", true, 1990},
}
b, err := json.Marshal(m)
if err != nil {
log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Println(string(b))
}
실행 결과는 다음과 같다.
[
{
"id": 1,
"title": "The Dark Knight",
"released": 2008
},
{
"id": 2,
"title": "The Godfather",
"adult": true,
"released": 1972
},
{
"id": 3,
"title": "GoodFellas",
"adult": true,
"released": 1990
}
]
Nested JSON
아래와 같이 장르가 추가된 중첩된 JSON 데이터를 처리할 경우가 생길 수 있다.
{
"id": 1,
"title": "The Dark Knight",
"released": 2008,
"genre": {
"id": 1,
"name": "drama"
}
}
이럴 경우는 struct를 다음과 같이 구성하면 된다.
type Movie struct {
Id int `json:"id"`
Title string `json:"title"`
Adult bool `json:"adult,omitempty"`
Year int `json:"released"`
Genre Genre `json:"genre"`
}
type Genre struct {
Id int `json:"id"`
Name string `json:"name"`
}
아니면 아래와 같이 작성해도 상관없다.
type Movie struct {
ID int `json:"id"`
Title string `json:"title"`
Adult bool `json:"adult,omitempty"`
Year int `json:"released"`
Genre struct {
ID int `json:"id"`
Name string `json:"name"`
} `json:"genre"`
}
저 같은 경우는 JSON 데이터를 다루기 위해 Go struct를 만들어야 하는 경우가 많은데요. 이런 작업은 JSON 필드가 많은 경우는 조금 귀찮은 작업이다. 아래 사이트를 이용하면 귀찮음을 덜 수 있다. 해당 사이트는 JSON를 입력하면 Go struct 변환해준다.
Inline type definitions 해제하면 아래와 같이 나온다.