ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Golang] encoding/json 패키지 알아보기
    Golang 2024. 6. 12. 07:23
    728x90
    반응형

    - 목차

     

    들어가며.

    Go 의 encoding/json 패키지는 JSON 데이터를 처리할 수 있도록 지원합니다.

    본 글에서는 encoding/json 패키지의 주요 기능과 다양한 예제를 통해 심층적으로 다뤄보겠습니다.

     

    Marshal ( struct 를 Json 으로 인코딩 ).

    encoding/json 패키지는 Marshal 함수를 제공합니다.

    Marshal 이라는 표현인 Encoding 과 유사한 개념으로 이해하시면 되며, Go struct 를 JSON으로 인코딩하는 역할을 수행합니다.

     

    Marshal 함수의 시그니처는 아래와 같습니다.

    Marshal 함수는 인자로써 interface{} 타입을 필요로 합니다.

    interface{} 타입은 다른 프로그래밍 언어의 Any 나 Object 같이 모든 데이터 타입을 의미하는 Wildcard 로 동작합니다.

    ( 좀 더 심층적으로 바라보자면 어떠한 Method 도 구현하지 않아도 되는 인터페이스이기 때문에 Wildcard 로 동작됨. )

    그리고 인코딩된 결과인 []byte 를 반환합니다.

     

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

     

    json.Marshal 함수의 활용 예시는 아래와 같습니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func JsonTestMain() {
    	p := Person{Name: "John Doe", Age: 30}
    	data, err := json.Marshal(p)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(string(data))
    	// {"name":"John Doe","age":30}
    }

     

    위 예시에서는 Person 이라는 구조체를 json.Marshal 함수를 통해서 인코딩을 적용합니다.

    주목할 점은 type Person struct 의 코드 블록 내부에 `json:"name"` 와 같은 태그가 존재합니다.

    만약 `json:"name"` 와 같은 태그가 존재하지 않는다면 구조체의 변수 식별자가 그대로 JSON 의 Key 로써 사용됩니다.

    Golang 은 구조적으로 외부 패키지에서의 접근을 허용하기 위해서 대분자로 시작하는 식별자를 사용해야합니다.

    이러한 구조적인 이유로 인해서 json 태그가 사용됩니다.

     

    구조체 내부에 json Tag 를 사용하지 않는다면 ?

    아래의 예시와 같이 type Person struct 코드 블록 내부에서 json Tag 를 사용하지 않는다면,

    Person 구조체의 변수 Name 과 Age 가 JSON Key 로써 사용됩니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string
    	Age  int
    }
    
    func JsonTestMain() {
    	p := Person{Name: "John Doe", Age: 30}
    	data, err := json.Marshal(p)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(string(data))
    	// {"Name":"John Doe","Age":30}
    }

     

     

     

    Unmarshal ( Json 을 struct 로 Decoding ).

    json.Unmarshal 함수를 통해서 JSON 을 Golang 구조체로 변환할 수 있습니다.

     

    json.Unmarshal 함수 의 시그니처는 아래와 같습니다.

    json.Marshal 과 반대로 []byte Slice 함수의 첫번째 인자로 받습니다.

    그리고 두번째 인자로 JSON 데이터를 역직렬화할 대상 객체를 전달합니다.

    Deserialization 결과를 반환하는 구조가 아니라 역직렬화할 대상 객체를 필요로 합니다.

     

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

     

    아래는 json.Unmarshal 함수의 활용 예시입니다.

    name 과 age 로 구성된 JSON 문자열을 var p Person 구조체로 역직렬화합니다.

    주목할 점은 &p 와 같이 포인터 형식으로 대상 객체를 전달해야 한다는 점입니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func JsonTestMain() {
    	data := []byte(`{"name": "John", "age": 30}`)
    
    	var p Person
    	err := json.Unmarshal(data, &p)
    	if err != nil {
    		fmt.Println("Error:", err)
    		return
    	}
    
    	fmt.Println(p)
    	// {John 30}
    }

     

     

    JSON 문자열과 구조체의 형식이 맞지 않을 때.

    만약 JSON 문자열과 구조체의 형식이 맞지 않을 때에 어떻게 동작하는지 알아보겠습니다.

     

    구조체에 존재하지 않는 JSON Key 가 있는 경우.

    아래의 예시와 같이 struct 의 변수인 name 과 age 이 이외에 city 라는 새로운 JSON Key 가 존재하는 경우에,

    구조체에 존재하지 않는 새로운 Key 는 역직렬화 대상에서 제외됩니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func JsonTestMain() {
    	data := []byte(`{"name": "John", "age": 30, "city": "Seoul"}`)
    
    	var p Person
    	err := json.Unmarshal(data, &p)
    	if err != nil {
    		fmt.Println("Error:", err)
    		return
    	}
    
    	fmt.Println(p)
    	// {John 30}
    }

     

    구조체에 존재하는 JSON Key 가 누라된 경우.

    아래의 예시와 같이 age 라는 구조체 변수가 JSON 에서 누락된 경우에는 age 가 int Zero Value 인 0 으로 초기하됩니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func JsonTestMain() {
    	data := []byte(`{"name": "John", "city": "Seoul"}`)
    
    	var p Person
    	err := json.Unmarshal(data, &p)
    	if err != nil {
    		fmt.Println("Error:", err)
    		return
    	}
    
    	fmt.Println(p)
    	// {John 0}
    }

     

     

    JSON 형식이 이상한 경우.

    JSON 형식에 문제가 있어서 파싱에 실패하는 경우도 존재합니다.

    이 경우에는 error 를 리턴하게 되며, Error Handling 이 필요합니다.

     

    package json
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name string `json:"name"`
    	Age  int    `json:"age"`
    }
    
    func JsonTestMain() {
    	data := []byte(`{""name": "John", "city": "Seoul"}`)
    
    	var p Person
    	err := json.Unmarshal(data, &p)
    	if err != nil {
    		fmt.Println("Error:", err)
    		// Error: invalid character 'n' after object key
    		return
    	}
    
    	fmt.Println(p)
    }

     

     

     

    반응형
Designed by Tistory.