0
0

【Go】json.Decoderとjson.Encoder

Last updated at Posted at 2024-07-17

はじめに

GoでJSONを扱う場合、最初に出会うのがjson.Marshaljson.Unmarshalだと思います。

しかし、これらはバッファにデータを格納したり、読み取ったりすることで実現されるのですが、DecoderEncoderを使えば、リクエストボディのストリームから直接デコードしたり、エンコードしたりするため、一時的なバッファを作成する必要がなく、メモリ使用量を抑えることができます。

またコードも簡潔に書くことができるため可読性も上がります。

今回は、そんなDecoderEncoderを使い方を確認します。

MarshalとUnmarshalを使用する場合

// POST /article
func PostArticleHandler(w http.ResponseWriter, req *http.Request){

	// Header.GETの返り値はstringなのでAtoiで整数に変換
	length, err := strconv.Atoi(req.Header.Get("Content-Length"))
	if err != nil {
		http.Error(w, "cannot get content length\n", http.StatusBadRequest)
		return
	}

	reqBodyBuffer := make([]byte, length)

	if _, err := req.Body.Read(reqBodyBuffer); !errors.Is(err, io.EOF) {
		http.Error(w, "fail to get request body\n", http.StatusBadRequest)
		return
	}

	defer req.Body.Close()

	var reqArticle models.Article

	if err := json.Unmarshal(reqBodyBuffer, &reqArticle); err != nil {
		http.Error(w, "fail to decode json≠\n", http.StatusBadRequest)
		return
	}

	jsonData, err := json.Marshal(reqArticle)
	if err != nil {
		http.Error(w, "fail to encode json\n", http.StatusInternalServerError)
		return
	}

	w.Write(jsonData)
}

Decoderを使用する場合

// POST /article
func PostArticleHandler(w http.ResponseWriter, req *http.Request) {
	var reqArticle models.Article
	if err := json.NewDecoder(req.Body).Decode(&reqArticle); err != nil {
		http.Error(w, "fail to decode json\n", http.StatusBadRequest)
	}

	article := reqArticle

	json.NewEncoder(w).Encode(article)
}

ストリームから直接リクエストデータを取るようにしたことで、デコード前の「Content-Lengthヘッダフィールドの値からバイトスライスを作り、そこにリクエストボディの中身を書き込む」という操作がまるまるいらなくなっています。直接デコーダの Decode メソッドを呼び出すだけで済むため、コードの見通しがとても良くなりました。

Decoderを使用するステップ

Decoder(Unmarshal)

ステップ1:リクエストボディをデコーダーに渡す
json.NewDecoderを使って、リクエストボディをデコードします。

var reqArticle models.Article
decoder := json.NewDecoder(req.Body)

ステップ2:デコードを実行する
Decodeメソッドを使って、リクエストボディを構造体にデコードします。

if err := decoder.Decode(&reqArticle); err != nil {
    http.Error(w, "fail to decode json\n", http.StatusBadRequest)
    return
}

Encoder(Marshal)

ステップ1: レスポンスのContent-Typeを設定する
クライアントに返すレスポンスがJSON形式であることを示すため、Content-Type ヘッダーを設定します。

w.Header().Set("Content-Type", "application/json")

ステップ2:レスポンスボディをエンコードする
json.NewEncoderを使って、構造体をJSON形式でレスポンスボディにエンコードします。

if err := json.NewEncoder(w).Encode(reqArticle); err != nil {
    http.Error(w, "fail to encode json\n", http.StatusInternalServerError)
    return
}
0
0
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
0
0