Go에서 JSON, HTTP client 써보기
Go에서 JSON을 사용하려면 먼저 표준 패키지인 ncoding/json 패키지를 import 해야 한다.
JSON
구조체 -> JSON
Go에서 구조체를 JSON 문자열로 변환하는 법부터 적는다.
좀 당황스러웟던 건 구조체의 변수가 첫 글자가 대문자여야 된다.
그리고 JSON 문자열 만들 때 리턴 값이 2개다
첫 번째 리턴은 JSON 문자열 데이터, 2번쨰 리턴은 문자열 만드는게 실패 했을 경우의 에러
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package main
import ( "encoding/json" "fmt" )
type User struct { ID string Name string Age int }
func main() { u := User{}
u.ID = "onepiece" u.Name = "luffy" u.Age = 18
uToJSON, err := json.Marshal(u)
if err != nil { panic(err) } else { fmt.Println("uToJSON:", string(uToJSON)) } }
|
위에서 언급한듯이 대문자를 써야 하기 때문에 내 JSON 문자열도 대문자로 들어간다
소문자로 하기 위해선 다음과 같이 해야 함.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main
import ( "encoding/json" "fmt" )
type User2 struct { ID string `json:"id"` Name string `json:"name"` Age int `json:"age"` }
func main() { u2 := new(User2)
u2.ID = "neverland" u2.Name = "emma" u2.Age = 10
u2ToJSON, _ := json.Marshal(u2)
fmt.Println("u2ToJSON:", string(u2ToJSON)) }
|
저런식으로 정의를 해줘야 함. 좀 귀찮게 되어 잇다;;
그리고 마지막에 string()으로 감싸줘야 문자열로 된다. 안 그러면 바이너리 같은 형식으로 되어 있음.
아래처럼 key안에 또 다른 key/value가 잇는 JSON 같은 경우에는 구조체 안의 구조체로.
1 2 3 4 5 6
| { "aa": "xx", "bb": { "z": "z" } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package main
import ( "encoding/json" "fmt" )
type Anime struct { Title string `json:"title"` Year int `json:"year"` Heroine Heroine }
type Heroine struct { Name string `json:"name"` Age int `json:"age"` }
func main() {
ani := new(Anime)
ani.Title = "방패용사 성공담" ani.Year = 2019 ani.Heroine.Name = "필로" ani.Heroine.Age = 1
aniToJSON, _ := json.Marshal(ani)
fmt.Println("aniToJSON:", string(aniToJSON)) }
|
맵 -> JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package main
import ( "encoding/json" "fmt" )
func main() { var myMap map[string]string
myMap = make(map[string]string)
myMap["a"] = "apple" myMap["b"] = "banana"
myMapToJSON, _ := json.Marshal(myMap)
fmt.Println("myMapToJSON:", string(myMapToJSON)) }
|
인터페이스 -> JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package main
import ( "encoding/json" "fmt" )
func main() { m := map[string]interface{}{ "a": "hi", "b": true, "c": 33, "d": []interface{}{ "array1", "array2", }, "e": map[string]interface{}{ "x": "x", "y": "y", "z": "z", }, }
mToJSON, _ := json.Marshal(m)
fmt.Println("mToJSON:", string(mToJSON)) }
|
JSON 파싱
읽을 샘플 데이터
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { "int": 3, "str": "aaa", "bool": true, "arr": [1,2,3], "obj": { "x": "x", "y": "y" }, "all": { "obj2": { "obj3": { "a": "a", "b": "b" }, "bool": false, "arr2": ["q", "w", "e"] } } }
|
io/ioutil라는 표준 패키지를 통해 파일을 읽을 수 잇음.
JSON -> 인터페이스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| package main
import ( "encoding/json" "io/ioutil" "fmt" )
func main() { myJSON, err := ioutil.ReadFile("./sample.json") if err != nil { panic(err) } else { fmt.Println("myJSON:", string(myJSON)) }
var myJSONparse map[string]interface{}
e := json.Unmarshal(myJSON, &myJSONparse)
if e != nil { panic(e) } else { fmt.Println(myJSONparse) }
myInt := myJSONparse["int"]
fmt.Println("myInt:", myInt)
myStr := myJSONparse["str"]
fmt.Println("myStr:", myStr)
myBool := myJSONparse["bool"]
fmt.Println("myBool:", myBool)
all := myJSONparse["all"]
fmt.Println(`myJSONparse["all"]:`, all)
obj2 := all.(map[string]interface{})["obj2"]
fmt.Println("obj2", obj2)
obj3 := obj2.(map[string]interface{})["obj3"]
fmt.Println("obj3:", obj3)
obj3A := obj3.(map[string]interface{})["a"]
fmt.Println("obj3.a:", obj3A)
obj3B := obj3.(map[string]interface{})["b"]
fmt.Println("obj3.b:", obj3B)
obj3C := obj3.(map[string]interface{})["c"]
fmt.Println("obj3.c:", obj3C)
obj2Bool := obj2.(map[string]interface{})["bool"]
fmt.Println("obj2.bool:", obj2Bool)
obj2Arr2 := obj2.(map[string]interface{})["arr2"]
fmt.Println("obj2.arr:", obj2Arr2) }
|
JSON -> 구조체
구조체를 조낸 정의해서 받아야 함.. -_-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package main
import ( "encoding/json" "io/ioutil" "fmt" )
type parseJSON struct { Int int `json:"int"` Str string `json:"str"` Bool bool `json:"bool"` Arr []int `json:"arr"` Obj FirstObj `json:"obj"` All FirstAll `json:"all"` }
type FirstObj struct { X string `json:"x"` Y string `json:"y"` }
type FirstAll struct { All SecondObj2 `json:"obj2"` }
type SecondObj2 struct { Obj3 thirdObj3 `json:"obj3"` Bool bool `json:"bool"` Arr2 []string `json:"arr2"` }
type thirdObj3 struct { A string `json:"a"` B string `json:"b"` }
func main() { myJSON, err := ioutil.ReadFile("./sample.json") if err != nil { panic(err) } else { fmt.Println("myJSON:", string(myJSON)) }
res := parseJSON{}
parseErr := json.Unmarshal(myJSON, &res)
if parseErr != nil { panic(parseErr) } else { fmt.Println(res) } }
|
HTTP
확인용으로 Express로 하나 띄움
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true }));
app.listen(3000, () => { console.log('listen'); });
app.get('/q', (req, res) => { res.status(200).send({code: 200, message: "hi"}); });
app.get('/q2', (req, res) => { res.status(403).send({code: 403, message: "403"}); });
app.get('/q3', (req, res) => { res.status(500).send({code: 500, message: "wrong"}); });
app.get('/q4', (req, res) => { console.log(req.query); res.status(200).send({code: 200, message: req.query.id}); });
app.get('/q5', (req, res) => { console.log('req header: ', req.headers); console.log('content-type: ', req.headers['content-type']); res.status(200).send({code: 200, message: "hi"}); });
app.post('/w', (req, res) => { console.log('body: ', req.body); res.status(200).send({code: 200, id: req.body.id, name: req.body.name}); });
app.post('/w2', (req, res) => { console.log('req header: ', req.headers); console.log('content-type: ', req.headers['content-type']); res.status(200).send({code: 200, title: req.body.title}); });
|
내장 패키지 net/http를 통해 가능함.
Get
쿼리스트링
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package main
import ( "fmt" "net/http" "net/url" "io/ioutil" )
func main() { req2, err := http.NewRequest("GET", "http://localhost:3000/q4", nil)
if err != nil { panic(err) }
q := url.Values{} q.Add("userId", "eqweqw12312") q.Add("name", "홍길동") q.Add("api_key", "zfxgrwwewrere")
req2.URL.RawQuery = q.Encode()
client2 := &http.Client{}
res2, err := client2.Do(req2)
if err != nil { panic(err) }
defer res2.Body.Close()
thisBody2, err := ioutil.ReadAll(res2.Body)
if err != nil { panic(err) }
fmt.Println("thisBody2", string(thisBody2)) }
|
본문 받기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package main
import ( "fmt" "encoding/json" "io/ioutil" "net/http" )
type parseJSON struct { Code int `json:"code"` Message string `json:"message"` }
func main() { resp, err := http.Get("http://localhost:3000/q")
if err != nil { panic(err) }
defer resp.Body.Close()
fmt.Println("resp", resp)
body, err := ioutil.ReadAll(resp.Body)
if err != nil { panic(err) }
fmt.Println("body", string(body))
thisRes := parseJSON{}
parseErr := json.Unmarshal(body, &thisRes)
if parseErr != nil { panic(parseErr) }
fmt.Println(thisRes.Code) }
|
POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package main
import ( "fmt" "net/http" "io/ioutil" "encoding/json" "bytes" )
type myParam struct { ID string `json:"id"` Name string `json:"name"` }
func main() { thisParam := myParam{}
thisParam.ID = "SAO" thisParam.Name = "kirito"
reqParams, _ := json.Marshal(thisParam)
buff := bytes.NewBuffer(reqParams)
fmt.Println("buff", buff)
postRes2, err := http.Post("http://localhost:3000/w", "application/json", buff)
if err != nil { panic(err) }
defer postRes2.Body.Close()
postResBody2, err := ioutil.ReadAll(postRes2.Body) if err == nil { fmt.Println("postResBody2", string(postResBody2)) } }
|
공통
헤더 추가
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package main
import ( "fmt" "net/http" "io/ioutil" "bytes" )
func main() {
var jsonStr = []byte(`{"title":"전생했더니 슬라임이었던 건에 대하여"}`)
req, err := http.NewRequest("POST", "http://localhost:3000/w2", bytes.NewBuffer(jsonStr))
if err != nil { panic(err) }
req.Header.Add("content-type", "application/json") req.Header.Add("Accept", "application/json")
client := &http.Client{}
res, err := client.Do(req)
if err != nil { panic(err) }
defer res.Body.Close()
thisBody, err := ioutil.ReadAll(res.Body)
if err != nil { panic(err) }
fmt.Println("thisBody", string(thisBody)) }
|
상태 확인
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| package main
import ( "net/http" "fmt" )
func main() {
ch1 := make(chan map[string]interface{})
ch2 := make(chan map[string]interface{})
ch3 := make(chan map[string]interface{})
go func() { resp, err := http.Get("http://localhost:3000/q")
if err != nil { panic(err) }
defer resp.Body.Close()
r := make(map[string]interface{})
r["statusCode"] = resp.StatusCode r["status"] = resp.Status
ch1 <- r
}()
go func() { resp, err := http.Get("http://localhost:3000/q2")
if err != nil { panic(err) }
defer resp.Body.Close()
r := make(map[string]interface{})
r["statusCode"] = resp.StatusCode r["status"] = resp.Status
ch2 <- r
}()
go func() { resp, err := http.Get("http://localhost:3000/q3")
if err != nil { panic(err) }
defer resp.Body.Close()
r := make(map[string]interface{})
r["statusCode"] = resp.StatusCode r["status"] = resp.Status
ch3 <- r
}()
for index := 0; index < 3; index++ { select { case msg1 := <-ch1: fmt.Println("첫 번쨰 리퀘스트 http status", msg1) case msg2 := <-ch2: fmt.Println("두 번쨰 리퀘스트 http status", msg2) case msg3 := <-ch3: fmt.Println("세 번쨰 리퀘스트 http status", msg3) } } }
|