Day 11 with Go-Lang
HTTP Post 호출
- JSON Data POST
JSON 데이터를 POST 하는 것은 이전 글 Plain Text 를 Post 하는 것과 비슷하다. 다만, 데이터가 JSON 포맷이므로 http.Post()
의 두번째 Parameter 에 application/json
을 적고, 세 번째 Parameter 에 JSON 으로 인코딩된 데이터를 전달하면 된다. 아래 예제에서 JSON 데이터는 encoding/json
표준 패키지의 Marshal()
함수를 사용해 임의의 구조체 데이터를 JSON 으로 변경하는 방법을 사용했다.
package main
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
)
type Person struct {
Name string
Age int
}
func main() {
person := Person{"Alex", 10}
pbytes, _ := json.Marshal(person)
buf := bytes.NewBuffer(pbytes)
resp, err := http.Post("http://httpbin.org/post", "application/json", buf)
if err != nil {
panic(err)
}
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
str := string(respBody)
println(str)
}
- XML Data POST
XML 데이터를 POST 하는 것은 위의 JSON 데이터를 POST 하는 것과 유사하다. 다만, 데이터를 XML 포맷으로 전달하므로 encoding/xml
패키지를 사용해 Marshalling 하고, MIME 타입을 application/xml
으로 지정한다.
package main
import (
"bytes"
"encoding/xml"
"io/ioutil"
"net/http"
)
type Person struct {
Name string
Age int
}
func main() {
person := Person{"Alex", 10}
pbytes, _ := xml.Marshal(person)
buf := bytes.NewBuffer(pbytes)
resp, err := http.Post("http://httpbin.org/post", "application/xml", buf)
// ...(생략)...
}
지금까지 위의 POST 예제들은 간편한 http.Post()
함수를 사용했는데, 보다 세밀한 제어를 위해 Request 객체를 만들어 여러 셋팅을 변경한 후, http.Client
를 통해 호출할 수 있다.
package main
import (
"bytes"
"encoding/xml"
"io/ioutil"
"net/http"
)
type Person struct {
Name string
Age int
}
func main() {
person := Person{"Alex", 10}
pbytes, _ := xml.Marshal(person)
buf := bytes.NewBuffer(pbytes)
// Request 객체 생성
req, err := http.NewRequest("POST", "http://httpbin.org/post", buf)
if err != nil {
panic(err)
}
// Content-Type 헤더 추가
req.Header.Add("Content-Type", "application/xml")
// Client 객체에서 Request 실행
client := &http.Client{}
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
panic(err)
}
// Response 체크
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
str := string(respBody)
println(str)
}
JSON 사용
- JSON
JSON (JavaScript Object Notation) 은 데이터를 교환하기 위한 포맷으로서 그 단순함과 유연함 때문에 널리 사용되고 있다. 특히 웹 브라우저와 웹서버 사이에서 데이터를 교환하는 데 많이 사용되고 있다. JSON 포맷은 기본적으로 Key-Value Pair 의 Collection 이다.
Go 에서 JSON 을 사용하기 위해 표준패키지 encoding/json
을 사용하면 된다. 표준패키지는 표준 패키지 에 모두 자세하게 설명되어 있는데, 이 중 JSON 관련 패키지는 JSON 패키지 에서 참조할 수 있다.
- JSON 인코딩
Go 데이터를 JSON 포맷으로 Encoding 하기 위해 encoding/json
패키지의 Marshal()
함수를 사용한다. 흔히 Go 구조체 또는 Map 데이터를 JSON 으로 Encoding 하게 되는데, 해당 Go 데이터 값을 json.Marshal()
의 Parameter 로 전달하면, JSON 으로 인코딩된 Byte 배열과 Error 객체를 리턴한다. 만약 JSON 으로 인코딩된 바이트 배열을 다시 문자열로 변경할 필요가 있다면, string(Byte 배열)
과 같이 변경이 가능하다.
한 가지 유의할 점은, JSON 의 Key 는 문자열이어야 한다. Go 구조체의 경우는 자동으로 필드명을 문자열로 사용하지만, Map 인 경우 map[string]T
처럼 Key 가 string 인 Map 만 지원한다. (Value ‘T’ 는 어떤 타입이든 상관 없음)
package main
import (
"encoding/json"
"fmt"
)
type Member struct {
Name string
Age int
Active bool
}
func main() {
// Go 데이터
mem := Member{"Alex", 10, true}
// JSON 인코딩
jsonBytes, err := json.Marshal(mem)
if err != nil {
panic(err)
}
// JSON 바이트를 문자열로 변경
jsonString := string(jsonBytes)
fmt.Println(jsonString)
}
- JSON 디코딩
JSON 으로 인코딩된 데이터를 다시 Decoding 하기 위해서, encoding/json
패키지의 Unmarshal()
함수를 사용한다. Unmarshal()
함수의 첫 번째 Parameter 에는 JSON 데이터를, 두 번째 Parameter 에는 출력할 구조체 (혹은 Map) 을 포인터로 지정한다. Return 값은 Error 객체이고, 에러가 없는 경우, 두 번째 Paramter 에 원래 데이터가 복원된다.
package main
import (
"encoding/json"
"fmt"
)
type Member struct {
Name string
Age int
Active bool
}
func main() {
// 테스트용 JSON 데이터
jsonBytes, _ := json.Marshal(Member{"Tim", 1, true})
// JSON 디코딩
var mem Member
err := json.Unmarshal(jsonBytes, &mem)
if err != nil {
panic(err)
}
fmt.Println(mem)
}
JSON 디코딩에서 만약 매칭되는 필드가 구조체에 없다면, 그 값은 무시되고 계속 처리된다. 즉, JSON 에 10 개의 Key-Value Pair 가 있는데, 출력 구조체는 그 중 3개의 필드만 가지고 있다면 3개 필드만 채워지고 나머지 키값은 무시된다.
또한 Go 의 JSON 패키지는 출력 구조체나 Map 을 미리 정의하지 않고 디코딩할 수도 있다.
XML 사용
- XML 인코딩
Go 데이터를 XML 포맷으로 Encoding 하기 위해서는 encoding/xml
패키지의 Marshal()
함수를 사용한다. 아래 예제는 Go 구조체를 XML 로 Encoding 하는 코드인데, 해당 Go 데이터 값을 xml.Marshal()
의 Parameter 로 전달하면 Marshal()
함수는 XML 로 인코딩된 Byte 배열과 Error 객체를 Return 한다.
package main
import "encoding/xml"
type Member struct {
Name string
Age int
Active bool
}
func main() {
mem := Member{"Alex", 10, true}
xmlBytes, err := xml.Marshal(mem)
if err != nil {
panic(err)
}
xmlString := string(xmlBytes)
println(xmlString)
}
- XML 디코딩
XML 로 Encoding 된 데이터를 다시 GO 타입으로 Decoding 하기 위해 encoding/xml
패키지의 Unmarshal()
함수를 사용한다. Unmarshal()
함수의 첫 Parameter 에는 XML 데이터를, 두 번째 Parameter 에는 출력할 구조체 포인터를 지정한다. Return 값은 Error 객체이고, 에러가 없는 경우, 두 번째 Parameter 에 원래 데이터가 복원된다.
package main
import (
"encoding/xml"
"fmt"
)
type Member struct {
Name string
Age int
Active bool
}
func main() {
// 테스트용 데이터
xmlBytes, _ := xml.Marshal(Member{"Tim", 1, true})
// XML Decoding
var mem Member
err := xml.Unmarshal(xmlBytes, &mem)
if err != nil {
panic(err)
}
fmt.Println(mem)
}
- XML 파일 읽기
흔히 XML 로 저장된 파일을 읽어 Go 타입으로 Decoding (혹은 Deserialization) 해 사용하는 경우가 많은데, 아래 예제는 이를 보여주는 것이다. 즉, 아래와 같은 XML Text 파일을 읽어 이를 Members 구조체로 Decoding 한 예이다.
<Members>
<Member>
<Name>Alex</Name>
<Age>10</Age>
<Active>true</Active>
</Member>
<Member>
<Name>Tim</Name>
<Age>12</Age>
<Active>false</Active>
</Member>
</Members>
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
type Member struct {
Name string
Age int
Active bool
}
type Members struct {
Member []Member
}
func main() {
// xml 파일 Open
fp, err := os.Open("test.xml")
defer fp.Close()
if err != nil {
panic(err)
}
// XML 파일 읽기
buf, err := ioutil.ReadAll(fp)
var members Members
xmlErr := xml.Unmarshal(buf, &members)
if xmlErr != nil {
panic(xmlErr)
}
fmt.Println(members)
}
Reference : 예제로 배우는 Go 프로그래밍