Kode program : JSON stream decoder

Golang – Pengenalan dan cara menggunakan JSON

JSON singkatan dari JavaScript Object Notation, merupakan stuktur format data yang bentuknya seperti Object di JavaScript. JSON merupakan struktur format data yang paling banyak digunakan saat kita membuat RESTful API.

Golang sudah menyediakan package JSON, dimana kita bisa menggunakan package ini untuk melakukan konversi data ke JSON (encode) atau sebaliknya (decode). Untuk detailnya dapat dilihat pada laman https://pkg.go.dev/encoding/json

Encode

Golang telah menyediakan function untuk melakukan konversi data ke JSON, yaitu menggunakan function json.Marshal(interface{}). Karena parameter nya adalah interface{}, maka kita bisa memasukkan tipe data apapun ke dalam function Marshal.

Buatlah project baru, dan di dalamnya buat file dengan nama encode_json_test.go dan masukkan baris kode berikut

package belajar_golang_test

import (
	"encoding/json"
	"fmt"
	"testing"
)

func logJson(data interface{}) {
	bytes, err := json.Marshal(data)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(bytes))
}

func TestEncode(t *testing.T) {
	logJson("Rendy")
	logJson(22)
	logJson(false)
	logJson([]string{"Rendy", "Wijaya"})
}
Kode program : JSON Marshal
Kode program : JSON Marshal

JSON Object

Sebelumnya kita telah mencoba melakukan ecode data seperti string, number, boolean, dan tipe data primitif lainnya. Walaupun memang bisa dilakukan, karena sesuai dengan kontrak interface{}, namun tidak sesuai dengan kontrak JSON, jika mengikuti kontrak json.org, data JSON bentuknya adalah Object dan Array.

JSON Object di golang direpresentasikan dengan tipe data Struct, dimana tiap attribute di JSON Object merupakan attribute di Struct.

Buat file baru dengan nama json_object_test.go dan masukkan abis kode berikut

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

type Customer struct {
	FirstName, LastName string
	Age                 int
}

func TestJSONObject(t *testing.T) {
	customer := Customer{
		FirstName: "Rendy",
		LastName:  "Wijaya",
		Age:       22,
	}

	bytes, err := json.Marshal(customer)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bytes))
}
Kode program : JSON Object
Kode program : JSON Object

Decode

Untuk melakukan konversi dari JSON ke tipe data di golang (Decode), kita bisa menggunakan function json.Unmarshal(byte[], interface{}). Dimana byte[] adalah data JSON nya, sedangkan interface{} adalah tempat menyimpan hasil konversi, biasanya berupa pointer.

Untuk mencobanya, buat kembali file baru dengan nama decode_json_test.go dan amsukkan baris kode berikut

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

func TestDecodeJSON(t *testing.T) {
	jsonString := `{"FirstName":"Rendy","LastName":"Wijaya","Age":22}`
	jsonBytes := []byte(jsonString)

	customer := &Customer{}

	err := json.Unmarshal(jsonBytes, customer)
	if err != nil {
		panic(err)
	}

	fmt.Println(customer)
	fmt.Println(customer.FirstName)
	fmt.Println(customer.LastName)
	fmt.Println(customer.Age)
}
Kode program : JSON Unmarshal
Kode program : JSON Unmarshal

JSON Array

Selain tipe data dalam bentuk Object, biasanya dalam JSON, kita kadang menggunakan tipe data Array, Array di JSON mirip dengan Array di JavaScript, dia bisa berisikan tipe data primitif, atau tipe data kompleks(Object atau Array). Di golang, JSON Array di representasikan dalam bentuk Slice. Konversi dari JSON atau ke JSON dilakukan secara otomatis, oleh package JSON menggunakan tipe data Slice.

Untuk mencobanya, pertama ubah Struct Customer yang sudah kita buat sebelumnya menjadi seperti berikut

type Customer struct {
	FirstName, LastName string
	Age                 int
	Hobbies []string
}

Selanjutnya buat juga file baru dengan nama json_array_test.go dan masukkan baris kode

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

func TestJSONArrayEncode(t *testing.T) {
	customer := Customer{
		FirstName: "Rendy",
		LastName:  "Wijaya",
		Age:       22,
		Hobbies:   []string{"Gaming", "Reading", "Coding"},
	}

	bytes, err := json.Marshal(customer)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bytes))
}

func TestJSONArrayDecode(t *testing.T) {
	jsonString := `{"FirstName":"Rendy","LastName":"Wijaya","Age":22,"Hobbies":["Gaming","Reading","Coding"]}`
	jsonBytes := []byte(jsonString)

	customer := &Customer{}

	err := json.Unmarshal(jsonBytes, customer)
	if err != nil {
		panic(err)
	}

	fmt.Println(customer)
	fmt.Println(customer.FirstName)
	fmt.Println(customer.LastName)
	fmt.Println(customer.Age)
	fmt.Println(customer.Hobbies)
}
Kode program : JSON Array
Kode program : JSON Array

Contoh diatas adalah cara kita melakukan encode dan decode JSON Array sederhana, nah bagaimana jika JSON nya complex, maka cara nya adalah seperti berikut

Peratma ubah terlebih dahulu Struct Customer dan kita juga akan membuat Struct baru dengan nama Address, kemudian kita masukkan ke Struct customer sebagai Slice of Struct agar Customer bisa membuat banyak Address.

type Address struct {
	Street, Country, PostalCode string
}

type Customer struct {
	FirstName, LastName string
	Age                 int
	Hobbies             []string
	Address             []Address
}

Selanjutnya untuk baris kode decode dan encode json complex adalah seperti berikut

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

func TestJSONArrayComplexEncode(t *testing.T) {
	customer := Customer{
		FirstName: "Rendy",
		Address: []Address{
			{
				Street:     "Jalan Belum Ada",
				Country:    "Indonesia",
				PostalCode: "9999",
			},
			{
				Street:     "Jalan Lagi DIbangun",
				Country:    "Indonesia",
				PostalCode: "8888",
			},
		},
	}

	bytes, err := json.Marshal(customer)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bytes))
}

func TestJSONArrayComplexDecode(t *testing.T) {
	jsonString := `{"FirstName":"Rendy","LastName":"","Age":0,"Hobbies":null,"Address":[{"Street":"Jalan Belum Ada","Country":"Indonesia","PostalCode":"9999"},{"Street":"Jalan Lagi DIbangun","Country":"Indonesia","PostalCode":"8888"}]}`
	jsonByte := []byte(jsonString)

	customer := &Customer{}

	err := json.Unmarshal(jsonByte, customer)
	if err != nil {
		panic(err)
	}

	fmt.Println(customer)
	fmt.Println(customer.FirstName)
	fmt.Println(customer.Address)
}
Kode program : JSON Array Complex
Kode program : JSON Array Complex

JSON Tag

Secara default attribute yang teradpat di Struct dan JSON akan di mapping sesuai dengan nama attribute yang sama (case sensitive). Kadang ada style yang berbeda antara penamaan attribute di Struct dan di JSON, misal di JSON kita ingin menggunakan snake_case, tapi di Struct, kita ingin menggunakan PascalCase.

Untungnya, package JSON mendukung Tag Reflection, kita bisa menambahkan tag rflection dengan nama json, lalu diikuti dengan attribute yang kita inginkan ketika konversi dari atau ke JSON.

Buatlah file baru dengan nama json_tag_test.go dan masukkan baris kode berikut

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

type Product struct {
	Id       string `json:"id,omitempty"`
	Name     string `json:"name,omitempty"`
	ImageURL string `json:"image_url,omitempty"`
}

func TestJSONTagEncode(t *testing.T) {
	product := Product{
		Id:       "P0001",
		Name:     "Apple Mac Book Pro",
		ImageURL: "http://example.com/image.png",
	}

	bytes, err := json.Marshal(product)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bytes))
}

func TestJSONTagDecode(t *testing.T) {
	jsonString := `{"id":"P0001","name":"Apple Mac Book Pro","image_url":"http://example.com/image.png"}`
	jsonBytes := []byte(jsonString)

	product := &Product{}
	err := json.Unmarshal(jsonBytes, product)
	if err != nil {
		panic(err)
	}

	fmt.Println(product)
	fmt.Println(product.Id)
	fmt.Println(product.Name)
	fmt.Println(product.ImageURL)
}
Kode program : JSON Tag
Kode program : JSON Tag

Map

Saat menggunakan JSON, kadang mungkin kita menemukan kasus data JSONnya dynamic, artinya attribute nya tidak menentu, bisa bertambah, bisa berkurang, dan tidak tetap. Pada kasus seperti itu, menggunakan Struct akan menyulitkan, karena pada Struct kita harus menentukan semua attributenya.

Untuk kasus seperti ini, kita bisa menggunakan tipe data map[string]interface{}, secara otomatis attribute akan menjadi key di map, dan value menjadi value di map, namun karena value berupa interface{}, maka kita harus lakukan konversi secara manual jika ingin mengambil value nya. Dan tipe data Map tidak mendukung JSON tag lagi.

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"testing"
)

func TestMapDecode(t *testing.T) {
	jsonString := `{"id":"P0001","name":"Apple Mac Book Pro","image_url":"http://example.com/image.png"}`
	jsonBytes := []byte(jsonString)

	var result map[string]interface{}
	json.Unmarshal(jsonBytes, &result)

	fmt.Println(result)
	fmt.Println(result["name"])
	fmt.Println(result["image_url"])
}

func TestMapEncode(t *testing.T) {
	product := map[string]interface{}{
		"id":        "P0001",
		"name":      "Apple Mac Book Pro",
		"image_url": "http://example.com/image.png",
	}

	bytes, _ := json.Marshal(product)
	fmt.Println(string(bytes))
}
Kode program : JSON Map
Kode program : JSON Map

Streaming Decoder

Sebelumnya kita belajar package json dengan melakukan konversi data JSON yang sudah dalam bentuk variable dan data string atau []byte. Pada kenyataannya, kadang data JSON nya berasal dari input berupa io.Reader(File, Network, Request Body).

Kita bisa saja membaca semua datanya terlebih dahulu, lalu simpan di variable, baru lakukan konversi dari JSON, namun hal ini sebenarnya tidak perlu dilakukan, karena package json memiliki fitur untuk membaca dari Stream.

Untuk membuat json Decoder, kita bisa gunakan function json.NewDecoder(reader), selanjutnya untuk membaca isi input reader dan konversikan secara langsung ke data di golang, cukup gunakan function Decode(interface{}).

Buatlah file baru dengan nama Customer.json dan masukkan baris kode berikut

{
    "FirstName": "Rendy",
    "Hobbies": null,
    "Address": [
        {
            "Street": "Jalan Belum Ada",
            "Country": "Indonesia",
            "PostalCode": "9999"
        },
        {
            "Street": "Jalan Lagi DIbangun",
            "Country": "Indonesia",
            "PostalCode": "8888"
        }
    ]
}

Setelah data sample nya dibuat, selanjutnya buat kembali file baru dengan nama decoder_test.go dan masukkan baris kode berikut

package belajar_golang

import (
	"encoding/json"
	"fmt"
	"os"
	"testing"
)

func TestStreamDecoder(t *testing.T) {
	reader, err := os.Open("Customer.json")
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(reader)

	customer := &Customer{}
	decoder.Decode(customer)

	fmt.Println(customer)
}
Kode program : JSON stream decoder
Kode program : JSON stream decoder

Streaming Encoder

Selain decoder, package json juga mendukung membuat Encoderyang bisa digunakan untuk menulis langsung JSON nya ke io.Writer. Dengan begitu kita tidak perlu menyimpan JSON datanya terlebih dahulu ke dalam variable string atau []byte, kita bisa langsung tulis ke io.Writer.

Untuk membuat encoder, kita bisa menggunakan function json.NewEncoder(writer), dan untuk menulis data sebagai JSON langsung ke writer, kita bisa gunakan function Encode(interface{}).

Untuk mencobanya, buatlah file baru dengan nama encoder_test.go dan masukkan baris kode berikut

package belajar_golang

import (
	"encoding/json"
	"os"
	"testing"
)

func TestEncoder(t *testing.T) {
	writer, err := os.Create("CustomerOut.json")
	if err != nil {
		panic(err)
	}
	encoder := json.NewEncoder(writer)

	customer := Customer{
		FirstName: "Rendy",
		LastName:  "Wijaya",
		Age:       22,
	}

	err = encoder.Encode(customer)
	if err != nil {
		panic(err)
	}
}
Kode program : JSON stream encoder
Kode program : JSON stream encoder

Penutup

Pada artikel kali ini kita telah belajar tentang json pada golang. Dan pada artikel selanjutnya saya akan membahas rest api pada golang.

Leave a reply:

Your email address will not be published.

Site Footer

Sliding Sidebar

About Me

About Me

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam.

Social Profiles

Facebook