공부/Go

golang convert []byte(byte array) to map[string]interface{}

토고미 2022. 6. 22. 13:47

모르는 json 형식이 들어왔을 때는 이전에 내가 쓴 글처럼 하면된다.

 

https://togomi.tistory.com/48

 

golang convert json to interface

go에서 json을 파싱할때 struct 구조를 모르거나, 키값 하나만 필요한데 struct는 너무 커서 곤란할 때가 있다. 그럴 땐 interface를 통해 파싱하면 간편하다. exampleJson이라는 변수에 json string이 담겨있다

togomi.tistory.com

 

하지만 위의 글에서는 인풋이 string이라는 전제가 깔려있다.

이런 전제가 만족되지 않는 경우가 있다.

 

http post의 request body를 처리하다가 이 이슈를 겪었다.

 

request를 처리하는 서버 쪽에서는 []byte 형식으로 들어올 뿐, 기존의 string은 참조할 수가 없다.

 

그러면 위의 글처럼 바로 json.Unmarshal을 하면 되지않을까 싶었는데 에러가 났다.

json: cannot unmarshal string into Go value of type map[string]interface {}

이유는 byte값을 출력해보면 안다.

# 기존에 클라이언트가 보낸(의도한) string
{"key1" : "value1"}

# request body로 받은 []byte
\"{\"key1\" : \"value1\"}\"

위와 같이 역슬래시 "\" 문자가 붙는다.

 

따라서 아래와 같이 해야한다.

1. string으로 변환한다.

2. '\' 문자를 제거한다.

    value값에 '"' 쌍따옴표 문자가 들어가는 경우 앞에 \\ 역슬래시 문자가 두개가 붙기 때문에 이를 고려해야한다.

3. 양쪽 끝의 '"' 쌍따옴표 문자를 제거한다.

4. json.Unmarshal([]byte(str)) 실행

    json.marshal을 이용해 []byte 타입으로 만들면 안되고, []byte(str) 처럼 바로 캐스팅해야한다.

 

전체 코드는 아래와 같다.

str := `{ "key1" : "value1" }`
byt, _ := json.Marshal(byt)

// str은 사용할 수 없고,
// byt 변수만 다룰 수 있는 상황이라고 가정

// 1. '\' 역슬래시 제거
body := strings.Replace(string(byt), `\"`, `"`, -1)

// 2. 양쪽 끝의 '"' 쌍따옴표 제거
body = body[1 : len(body)-1]

// 3. 2개 역슬래시를 하나로 줄이기
body = strings.Replace(body, `\\`, `\`, -1)  

// 4. UnMarshal
var data map[string]interface{}
if err := json.Unmarshal([]byte(body), &data); err != nil {
	fmt.Println(err)
} else {
	fmt.Println(data)
}

 

파싱된 map 구조체에서 값을 참조하는 방법은 이전에 내가 쓴 글을 참조 바란다.

 

아래 링크는 내가 업무를 하며 go playground에서 테스트한 코드이다.

https://go.dev/play/p/1uklNFGbv2O