12
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

golangのjson parseについて(marshal/decode/json.RawMessage)

Posted at
  • golangでjsonをparseする時、いくつか方法があるので、パターン別に自分の使い分けを解説。

jsonテキストをstructの変数に流し込む(json.Unmarshal)

  • jsonテキストをパースする一番よくあるパターン。まあ現実的には同じ関数内で作ったjsonテキストをparseなどしないが…
package main

import (
	"encoding/json"
	"fmt"
)

type jsonData struct {
	Name string `json:"name"`
	Num  int    `json:"num"`
}

func main() {
	jsonStr := `{"name":"Apple","num":3}`
	jsonBytes := []byte(jsonStr)
	var d jsonData
	json.Unmarshal(jsonBytes, &d)
	fmt.Println(d.Name, d.Num)
}

io.Readerから1回でstructの変数に流し込む場合(json.NewDecoder)

  • よくあるパターン。例えばサーバのapiにhttp.Getでリクエストして、Response typeのBody fieldをparseするような場合だ。
  • サンプルとかも多いので解説の必要はないだろう。シンプルに以下でいい。
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type respBody struct {
	Result  int
	Message string
}

func main() {
	resp, err := http.Get("どっかのAPI")
	var data respBody
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		fmt.Println(err.Error())
	}
}
  • このパターンの場合、resp.Bodyio.Readerで読み込みは一度しかできない。

io.Readerから複数回でstructの変数に流し込む場合(json.Unmarshal, json.RawMessage)

  • APIからのresponseをparseする場合に割とあるのがこれ。responseの構造がapiの結果によって変わる場合などだ。200応答と、500応答とでpayloadの構造が違う…とか。
  • この場合、一部のfieldだけparseしてから残りを処理分岐したい。
  • io.Readerのままだと複数回読み込みはできないので、[]byteなどでデータを持っておく必要があるが、加えて一度parseしたfieldを再度parseするというのはどうにもダサい。
  • 以下のようにparseを遅らせたい項目をjson.RawMessageにしておくと、後からjson.Unmarshalを行うことができる。
  • json.RawMessage[]byteを型定義したものなので、そのままjson.Unmarshalで処理可能だ。
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type respBody struct {
	Result  string          `json:"result"`
	Payload json.RawMessage `json:"payload"`
}

type respPayloadOK struct {
	Message string `json:"message"`
}

type respPayloadErr struct {
	ErrCode    int    `json:"errCode"`
	ErrMessage string `json:"errMessage"`
}

func main() {
	resp, err := http.Get("どっかのAPI")

	bodyBytes, err := ioutil.ReadAll(resp.Body)

	var data respBody

	if err = json.Unmarshal(bodyBytes, &data); err != nil {
		fmt.Println(err.Error())
		return
	}

	if data.Result != "ok" {
		var payloadErr respPayloadErr
		if err = json.Unmarshal(data.Payload, &payloadErr); err != nil {
			fmt.Println(err.Error())
			return
		}
		fmt.Println(payloadErr.ErrCode, payloadErr.ErrMessage)
		return
	}

	var payload respPayloadOK
	if err = json.Unmarshal(data.Payload, &payload); err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(payload.Message)
}
12
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?