json形式のデータを扱う機会はとても多い。フロントエンドとバックエンド間でAPI通信をしようとした時、必要になってくる処理の1つが、json形式のデータを受け取った後、編集できる形式に変換したり、json形式のデータに戻したりというものである。
エンコードやデコードって何?
エンコードは、データを別の形式に変換すること。主にフロントエンドで使われる。フロントエンドにて”json.stringify()でエンコードした”ということは、すなわち”あるjavascriptの値やオブジェクトをjson形式に変換した”ということを指す。json.stringify()を使うことで、json形式のオブジェクトとして使えるようになる。
const requestBody: any = message;
let requestOptions: RequestInit = {
body: JSON.stringify(requestBody),
method: method,
headers: headers,
credentials: "include",}
一方でデコードは、エンコードされたものを元の形式に戻すこと。主にバックエンドで使われる。jsonで言えば、エンコードされたものを元の形式に戻ることがデコード。フロントエンドではjson.parseを使う。Goではjson.Marshalを使って構造体をJSON形式に変換する。JSON形式に変換してネットワーク越しに送信したいときに使う。逆にjson形式で受け取った値を指定した構造体に変換するのがjson.Unmarshal。ネットワーク越しにデータを受け取った時に使う。
func (app *application) writeJSON(w http.ResponseWriter, status int, data interface{}, headers ...http.Header) error {
out, err := json.Marshal(data)
if err != nil {
return err
}
つぎにjson.NewDecoder。これもjson.Unmarshalと同様に、json形式で受け取ったデータを構造体に変換するもの。json.NewDecoderでは、Decodeメソッドを用いて、データ読み込みの終わりにio.EOFエラーを返す処理が必要になる。大規模なデータを読み込む場合は特にNewDecoderの方が有用。
func (app *application) readJSON(w http.ResponseWriter, r *http.Request, data interface{}) error {
maxBytes := 1024 * 1024 //1 mega byte
r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes))
dec := json.NewDecoder(r.Body) //decoder
dec.DisallowUnknownFields()
json.Unmarshalとjson.NewDecoderの違い
さて、json.Unmarshalとjson.NewDecoderは性質が似ている。両方ともjson形式で受け取ったデータを構造体に変換する。違いは、json.Unmarshalはバイト配列のJSONデータを一度に読み込んでGoのデータ構造に変換するのに対し、json.NewDecoderはストリーム形式で提供されるJSONデータを逐次的に読み込んでGoのデータ構造に変換するために使用される。
ストリーム形式で提供されるJSONデータとは、大きなJSONデータが一度に全て提供されるのではなく、小さな塊に分割され、逐次的に提供される形式のことを指す。ストリーム形式で提供されるJSONデータは、ファイルやネットワークなどの入力ソースから一部ずつ読み込まれるため、一度にすべてのデータをメモリに読み込む必要がない。これは、大規模なJSONデータを処理する場合に特に有用。例えば、TwitterのストリーミングAPIを使用してリアルタイムでツイートを受信する場合、大量のJSONデータがストリーム形式で提供される。この場合、json.NewDecoderを使用することで、受信したJSONデータを逐次的に処理していくことができる。
なお、ストリーム形式で提供されるJSONデータは、開始と終了が明確でないため、逐次的に読み込みながらデータが終了したかどうかを判断する必要がある。これは、json.NewDecoderのDecodeメソッドを使用することで実現できる。Decodeメソッドは、ストリームから次のJSONオブジェクトを読み込み、それをGoのデータ構造に変換する。もしストリームの終端に到達した場合、Decodeメソッドはio.EOFエラーを返す。
io.EOF
は、Go言語の標準ライブラリで定義されているエラーの一つで”End Of File”の略称。これは、入力ソースから読み込み操作を行った際に、ソースの終端に到達したことを示すエラー。例えば、ファイルを読み込んでいる際に、ファイルの最後まで読み込んだ場合、io.EOF
が返される。同様に、ネットワーク通信を行っている場合にも、データの受信が終了した場合にio.EOF
が返される。io.EOF
は、エラーとして扱われますが、単なる終端に到達したことを示すため、エラーとして処理される必要はない。json.NewDecoder
のDecode
メソッドを使用する際には、ストリームから次のJSONオブジェクトを読み込んだ際にio.EOF
が返された場合、それがストリームの終端であることを示しているため、特別な処理を行うことができる。
コメント