Decoding Base64 di Go sering ditemui โ inspeksi JWT, lampiran file biner, payload API dari layanan cloud. Paket standar encoding/base64di Go menangani semua itu, namun memilih varian encoding yang salah (standar vs URL-safe, berpadding vs tanpa padding) adalah sumber paling umum error โillegal base64 dataโ. Panduan ini membahas StdEncoding, URLEncoding, RawURLEncoding, streaming decoding dengan base64.NewDecoder, inspeksi payload JWT, dan empat kesalahan yang hampir selalu dialami pertama kali. Untuk decoding satu kali di browser, Dekoder Base64 ToolDeck langsung menyelesaikan pekerjaan tanpa perlu menulis satu baris kode pun.
- โencoding/base64 adalah bagian dari standard library Go โ tidak perlu go get
- โGunakan RawURLEncoding untuk token JWT dan sebagian besar API modern (tanpa padding, alfabet URL-safe)
- โStdEncoding menggunakan + dan / dengan padding =; URLEncoding menggantinya dengan - dan _ namun tetap berpadding
- โbase64.NewDecoder membungkus io.Reader apa pun untuk streaming decode tanpa memuat ke memori
- โSelalu periksa error yang dikembalikan โ padding tidak valid dan alfabet yang salah menghasilkan illegal base64 data
Apa itu Decoding Base64?
Encoding Base64 merepresentasikan data biner sebagai teks ASCII menggunakan 64 karakter yang dapat dicetak (AโZ, aโz, 0โ9, ditambah dua karakter tambahan). Decoding membalik proses ini โ mengonversi representasi ASCII tersebut kembali menjadi byte aslinya. Setiap 4 karakter Base64 di-decode menjadi tepat 3 byte. Skema ini ada karena banyak lapisan transport (email, HTTP header, field JSON) dirancang untuk teks, bukan biner mentah. Berikut tampilan proses bolak-baliknya:
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Raw bytes โ Base64 encoded โ decoded back to raw bytes
original := []byte("service_token:xK9mP2qR")
// Encoded: "c2VydmljZV90b2tlbjp4SzltUDJxUg=="
encoded := base64.StdEncoding.EncodeToString(original)
decoded, _ := base64.StdEncoding.DecodeString(encoded)
fmt.Println(string(decoded) == string(original)) // true
}Decode Base64 di Go dengan encoding/base64
Paket encoding/base64 sudah disertakan dalam Go โ tanpa dependensi eksternal. Paket ini menyediakan empat varian encoding yang sudah didefinisikan sebagai variabel tingkat paket. Fungsi yang paling sering digunakan untuk input string adalah DecodeString, yang mengembalikan slice byte dan sebuah error.
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
// Standard Base64 โ the alphabet uses + and / with = padding
encoded := "eyJob3N0IjoiZGItcHJvZC51cy1lYXN0LTEiLCJwb3J0Ijo1NDMyfQ=="
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode error: %v", err)
}
fmt.Println(string(decoded))
// {"host":"db-prod.us-east-1","port":5432}
}Metode Decode bekerja pada slice byte, bukan string, dan menulis hasilnya ke dalam buffer tujuan yang sudah dialokasikan. Anda perlu menentukan ukuran buffer dengan benar โ gunakan base64.StdEncoding.DecodedLen(len(src)) untuk mendapatkan ukuran maksimum (bisa beberapa byte lebih besar dari panjang aktual hasil decode karena padding).
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
src := []byte("eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9")
dst := make([]byte, base64.RawStdEncoding.DecodedLen(len(src)))
n, err := base64.RawStdEncoding.Decode(dst, src)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(dst[:n]))
// {"host":"db-prod","port":5432}
}DecodedLen mengembalikan batas atas, bukan panjang yang tepat. Selalu gunakan nilai kembalian n dari Decode untuk memotong hasil dengan benar: dst[:n].StdEncoding vs URLEncoding โ Memilih Varian yang Tepat
Di sinilah kebanyakan kebingungan terjadi. encoding/base64 di Go menyediakan empat objek encoding, dan memilih yang salah dijamin menghasilkan error. Perbedaannya bergantung pada dua hal: alfabet dan padding.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// JWT header payload โ URL-safe, no padding
jwtHeader := "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjMtMDkifQ"
// Wrong: StdEncoding fails on URL-safe input without padding
_, err1 := base64.StdEncoding.DecodeString(jwtHeader)
fmt.Println("StdEncoding error:", err1)
// StdEncoding error: illegal base64 data at input byte 43
// Correct: RawURLEncoding โ no padding, URL-safe alphabet
decoded, err2 := base64.RawURLEncoding.DecodeString(jwtHeader)
fmt.Println("RawURLEncoding ok:", err2, "โ", string(decoded))
// RawURLEncoding ok: <nil> โ {"alg":"RS256","kid":"2023-09"}
}Empat varian dalam penjelasan sederhana:
Aturan praktis saya: jika berasal dari JWT, alur OAuth, atau SDK cloud provider, gunakan RawURLEncoding terlebih dahulu. Jika berasal dari lampiran email atau form web lawas, coba StdEncoding. Pesan error selalu menunjukkan posisi byte tepat di mana decoding gagal.
Decode Base64 dari File dan Respons API
Membaca file yang di-encode Base64
File biner (gambar, PDF, sertifikat) kadang disimpan dalam format Base64 di disk. Baca filenya, hapus spasi di akhir, lalu decode:
package main
import (
"encoding/base64"
"fmt"
"log"
"os"
"strings"
)
func main() {
raw, err := os.ReadFile("certificate.pem.b64")
if err != nil {
log.Fatalf("read file: %v", err)
}
// Strip newlines โ Base64 files often have line breaks every 76 chars
cleaned := strings.ReplaceAll(strings.TrimSpace(string(raw)), "\n", "")
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatalf("decode: %v", err)
}
if err := os.WriteFile("certificate.pem", decoded, 0600); err != nil {
log.Fatalf("write: %v", err)
}
fmt.Printf("decoded %d bytes โ certificate.pem\n", len(decoded))
}Men-decode field Base64 dari respons JSON API
API cloud sering mengembalikan data biner (kunci enkripsi, blob bertanda tangan, thumbnail) sebagai string Base64 di dalam JSON. Unmarshal JSON-nya terlebih dahulu, kemudian decode field yang dituju:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
)
type SecretResponse struct {
Name string `json:"name"`
Payload string `json:"payload"` // Base64-encoded secret value
Version int `json:"version"`
}
func fetchAndDecodeSecret(secretURL string) ([]byte, error) {
resp, err := http.Get(secretURL)
if err != nil {
return nil, fmt.Errorf("http get: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
var secret SecretResponse
if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil {
return nil, fmt.Errorf("decode json: %w", err)
}
value, err := base64.StdEncoding.DecodeString(secret.Payload)
if err != nil {
return nil, fmt.Errorf("decode base64: %w", err)
}
return value, nil
}
func main() {
value, err := fetchAndDecodeSecret("https://api.example.com/secrets/db-password")
if err != nil {
log.Fatalf("fetch secret: %v", err)
}
fmt.Printf("secret value: %s\n", value)
}fmt.Errorf("decode base64: %w", err) daripada kehilangan konteks. Pesan error asli dari encoding/base64 menyertakan posisi byte tempat kegagalan terjadi, yang berguna saat debugging.Streaming File Base64 Berukuran Besar
Memuat file Base64 berukuran 500 MB ke memori dengan os.ReadFile lalu memanggil DecodeString menggunakan sekitar 750 MB RAM (string terenkode ditambah byte hasil decode). base64.NewDecoder membungkus io.Reader apa pun dan melakukan decode secara bertahap, menjaga penggunaan memori hampir konstan. Gabungkan dengan io.Copy untuk pipeline streaming yang bersih:
package main
import (
"encoding/base64"
"fmt"
"io"
"log"
"os"
)
func streamDecodeFile(srcPath, dstPath string) error {
src, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("open source: %w", err)
}
defer src.Close()
dst, err := os.Create(dstPath)
if err != nil {
return fmt.Errorf("create dest: %w", err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
written, err := io.Copy(dst, decoder)
if err != nil {
return fmt.Errorf("stream decode: %w", err)
}
fmt.Printf("written %d bytes to %s\n", written, dstPath)
return nil
}
func main() {
if err := streamDecodeFile("backup.tar.b64", "backup.tar"); err != nil {
log.Fatal(err)
}
}base64.NewDecoder mengharapkan data Base64 yang bersih dan tidak terputus. Jika file sumber memiliki jeda baris (umum pada file PEM dan MIME), bungkus reader sumber dengan reader penghapus baris atau proses file terlebih dahulu untuk menghapus newline sebelum melakukan streaming.Decoding Base64 dari Command Line
Sebagian besar developer Go pertama kali menggunakan command line saat debugging. Setiap sistem macOS dan Linux sudah dilengkapi base64; di Windows, PowerShell memiliki ekuivalen bawaan. Untuk inspeksi cepat payload API, cara ini lebih cepat daripada menulis skrip Go.
# Decode a Base64 string (Linux / macOS)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode
# {"host":"db-prod","port":5432}
# Decode and pretty-print with jq (pipe the JSON output)
echo "eyJob3N0IjoiZGItcHJvZCIsInBvcnQiOjU0MzJ9" | base64 --decode | jq .
# {
# "host": "db-prod",
# "port": 5432
# }
# Decode a Base64-encoded file to binary
base64 --decode < encrypted_payload.b64 > encrypted_payload.bin
# macOS uses -D flag instead of --decode
echo "c2VjcmV0LXRva2Vu" | base64 -DUntuk memeriksa token JWT tanpa alat yang terpasang, tempel token ke Dekoder Base64 ToolDeck โ pisahkan berdasarkan titik dan decode setiap bagiannya.
Alternatif Berkinerja Tinggi: encoding/base64 Sudah Cepat
Berbeda dengan Python, di mana orjson vs json adalah perdebatan performa yang bermakna, encoding/base64 di Go sudah dioptimalkan dengan assembly dan benar-benar cepat untuk sebagian besar beban kerja. Namun demikian, jika Anda memproses jutaan record dalam loop ketat, filippo.io/base64 menyediakan decoding berakselerasi SIMD dengan API yang bisa langsung menggantikan paket standar.
go get filippo.io/base64
package main
import (
"fmt"
"log"
"filippo.io/base64"
)
func main() {
// Drop-in replacement โ same API as encoding/base64
encoded := "eyJob3N0IjoiY2FjaGUtcHJvZCIsInBvcnQiOjYzNzl9"
decoded, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"host":"cache-prod","port":6379}
}Peningkatan performa paling terlihat pada amd64 dengan dukungan AVX2 โ benchmark menunjukkan peningkatan throughput 2โ4x pada input berukuran besar. Untuk decoding respons API sehari-hari (beberapa ratus byte setiap kali), tetap gunakan standard library.
Men-decode Payload JWT Base64 di Go
Inspeksi JWT muncul di hampir setiap layanan backend. Berdasarkan pengalaman saya, sebagian besar sesi debugging berujung pada pertanyaan โapa sebenarnya isi token ini?โ โ dan Anda bisa menjawabnya tanpa perlu mengimpor library JWT lengkap. Token memiliki tiga segmen yang di-encode Base64url dan dipisahkan oleh titik. Segmen tengah adalah payload yang sebenarnya Anda butuhkan:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"strings"
)
type JWTPayload struct {
Subject string `json:"sub"`
Issuer string `json:"iss"`
Expiry int64 `json:"exp"`
Roles []string `json:"roles"`
}
func decodeJWTPayload(token string) (*JWTPayload, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid JWT: expected 3 segments, got %d", len(parts))
}
// JWT uses RawURLEncoding โ URL-safe alphabet, no = padding
raw, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("decode payload: %w", err)
}
var payload JWTPayload
if err := json.Unmarshal(raw, &payload); err != nil {
return nil, fmt.Errorf("unmarshal payload: %w", err)
}
return &payload, nil
}
func main() {
token := "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3ItNDQyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIsImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJhdWRpdG9yIl19.SIGNATURE"
payload, err := decodeJWTPayload(token)
if err != nil {
log.Fatalf("jwt: %v", err)
}
fmt.Printf("Subject: %s\n", payload.Subject)
fmt.Printf("Issuer: %s\n", payload.Issuer)
fmt.Printf("Roles: %v\n", payload.Roles)
// Subject: usr-442
// Issuer: auth.example.com
// Roles: [admin auditor]
}Kesalahan Umum
Saya pernah menemukan keempat kesalahan ini dalam review kode nyata โ dua yang pertama hampir selalu muncul setiap kali seseorang mengintegrasikan auth provider baru.
Masalah: Token JWT dan token OAuth menggunakan alfabet Base64 URL-safe (- dan _). Memberikannya ke StdEncoding.DecodeString gagal dengan 'illegal base64 data'.
Solusi: Periksa sumber input Anda: token dari sistem autentikasi menggunakan RawURLEncoding; lampiran biner menggunakan StdEncoding.
// JWT header โ URL-safe, no padding token := "eyJhbGciOiJSUzI1NiJ9" decoded, err := base64.StdEncoding.DecodeString(token) // err: illegal base64 data at input byte 19
// JWT header โ correct encoding
token := "eyJhbGciOiJSUzI1NiJ9"
decoded, err := base64.RawURLEncoding.DecodeString(token)
// decoded: {"alg":"RS256"}
// err: nilMasalah: Decode menulis ke buffer yang sudah dialokasikan dan mengembalikan jumlah byte yang benar-benar ditulis. DecodedLen mengembalikan batas atas, sehingga bagian akhir buffer mungkin berisi byte sampah.
Solusi: Selalu potong hasilnya dengan dst[:n] โ bukan dst[:len(dst)].
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src))) base64.StdEncoding.Decode(dst, src) fmt.Println(string(dst)) // may include trailing zero bytes
dst := make([]byte, base64.StdEncoding.DecodedLen(len(src)))
n, err := base64.StdEncoding.Decode(dst, src)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(dst[:n])) // correct โ only the decoded bytesMasalah: String Base64 yang disalin dari terminal, email, atau file konfigurasi sering memiliki newline atau spasi di akhirnya. Memberikannya langsung ke DecodeString gagal pada karakter spasi tersebut.
Solusi: Panggil strings.TrimSpace (dan strings.ReplaceAll untuk newline yang tersisip) sebelum decoding.
// Value read from a config file with a trailing newline encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" decoded, err := base64.StdEncoding.DecodeString(encoded) // err: illegal base64 data at input byte 24
encoded := "c2VydmljZV9rZXk6eEtNcDI=\n" cleaned := strings.TrimSpace(encoded) decoded, err := base64.StdEncoding.DecodeString(cleaned) // decoded: "service_key:xKMp2" // err: nil
Masalah: Memanggil string(decoded) pada data biner (gambar, payload terkompresi) menghasilkan string UTF-8 yang tidak valid. String Go dapat menampung byte arbitrer, namun beberapa operasi dapat merusak isinya.
Solusi: Pertahankan data biner sebagai []byte di seluruh pipeline Anda. Hanya panggil string(decoded) jika konten yang di-decode dijamin berupa teks.
decoded, _ := base64.StdEncoding.DecodeString(pngBase64)
// Treating binary PNG as a string loses data
imageStr := string(decoded)
os.WriteFile("image.png", []byte(imageStr), 0644) // may corruptdecoded, err := base64.StdEncoding.DecodeString(pngBase64)
if err != nil {
log.Fatal(err)
}
// Write bytes directly โ no string conversion
os.WriteFile("image.png", decoded, 0644)Perbandingan Metode
Semua varian sudah tersedia dalam standard library โ tidak ada dependensi eksternal untuk semua metode ini.
Untuk token JWT dan alur OAuth: RawURLEncoding. Untuk lampiran email dan data MIME: StdEncoding. Untuk file biner berukuran besar dari disk atau jaringan: bungkus reader dengan base64.NewDecoder โ menjaga penggunaan memori tetap flat terlepas dari ukuran file. Butuh alfabet kustom? base64.NewEncoding(alphabet) membangun objek encoding baru untuk kasus penggunaan khusus.
Untuk pengecekan satu kali yang cepat selama pengembangan, dekoder Base64 online lebih cepat daripada menjalankan program Go.
Pertanyaan yang Sering Diajukan
Bagaimana cara men-decode string Base64 di Go?
Import encoding/base64 dan panggil base64.StdEncoding.DecodeString(s). Fungsi ini mengembalikan ([]byte, error) โ selalu periksa error-nya. Jika string menggunakan karakter URL-safe (- dan _ sebagai pengganti + dan /), gunakan base64.URLEncoding.DecodeString. Untuk token JWT dan sebagian besar API modern, RawURLEncoding (tanpa padding) adalah pilihan yang tepat.
package main
import (
"encoding/base64"
"fmt"
"log"
)
func main() {
encoded := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
decoded, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
log.Fatalf("decode: %v", err)
}
fmt.Println(string(decoded))
// {"alg":"HS256","typ":"JWT"}
}Apa perbedaan antara StdEncoding dan URLEncoding di Go?
StdEncoding menggunakan alfabet Base64 standar dengan karakter + dan / serta padding = โ didefinisikan dalam RFC 4648 ยง4. URLEncoding mengganti + dengan - dan / dengan _ sehingga output aman digunakan dalam URL dan HTTP header tanpa percent-encoding โ didefinisikan dalam RFC 4648 ยง5. Gunakan URLEncoding untuk token JWT, token OAuth, dan data apa pun yang disematkan dalam query string.
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Standard: may contain + / and = characters
std := base64.StdEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(std) // "aGVsbG8vd29ybGQ="
// URL-safe: replaces + with - and / with _
url := base64.URLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(url) // "aGVsbG8vd29ybGQ=" (same โ diff shows with different bytes)
// JWT headers never have padding โ use RawURLEncoding
raw := base64.RawURLEncoding.EncodeToString([]byte("hello/world"))
fmt.Println(raw) // "aGVsbG8vd29ybGQ" (no trailing =)
}Bagaimana cara memperbaiki error "illegal base64 data" di Go?
Error ini berarti input mengandung karakter di luar alfabet yang diharapkan, atau padding-nya salah. Tiga penyebab umum: menggunakan StdEncoding pada input URL-safe (ganti ke URLEncoding), menggunakan encoder berpadding pada input tanpa padding (ganti ke RawStdEncoding/RawURLEncoding), atau ada spasi/newline di akhir string. Hapus spasi dengan strings.TrimSpace sebelum melakukan decoding.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
// Input from a webhook payload โ has newlines stripped from wire format
raw := " aGVsbG8gd29ybGQ= \n"
cleaned := strings.TrimSpace(raw)
decoded, err := base64.StdEncoding.DecodeString(cleaned)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(decoded)) // hello world
}Bagaimana cara stream-decode file Base64 berukuran besar di Go?
Gunakan base64.NewDecoder(base64.StdEncoding, reader) yang membungkus io.Reader apa pun dan melakukan decoding secara langsung. Hubungkan dengan io.Copy untuk menulis ke tujuan tanpa memuat seluruh file ke memori. Ini adalah pola standar untuk men-decode lampiran biner atau payload data berukuran besar yang di-encode dalam Base64.
package main
import (
"encoding/base64"
"io"
"log"
"os"
)
func main() {
src, err := os.Open("attachment.b64")
if err != nil {
log.Fatal(err)
}
defer src.Close()
dst, err := os.Create("attachment.bin")
if err != nil {
log.Fatal(err)
}
defer dst.Close()
decoder := base64.NewDecoder(base64.StdEncoding, src)
io.Copy(dst, decoder)
}Bisakah saya men-decode payload JWT Base64 di Go tanpa library JWT?
Bisa. JWT terdiri dari tiga segmen yang di-encode Base64url dan dipisahkan oleh titik. Pisahkan berdasarkan "." dan decode segmen kedua (indeks 1) dengan base64.RawURLEncoding.DecodeString โ header dan payload JWT menggunakan alfabet URL-safe tanpa padding. Segmen tanda tangan (indeks 2) bersifat biner dan biasanya hanya dibutuhkan untuk verifikasi.
package main
import (
"encoding/base64"
"fmt"
"log"
"strings"
)
func main() {
token := "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c3ItOTAxIiwicm9sZSI6ImFkbWluIn0.SIG"
parts := strings.Split(token, ".")
if len(parts) < 2 {
log.Fatal("invalid JWT format")
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
log.Fatalf("decode payload: %v", err)
}
fmt.Println(string(payload))
// {"sub":"usr-901","role":"admin"}
}Encoding apa yang harus digunakan untuk men-decode data Base64 dari respons API HTTP?
Periksa dokumentasi API atau inspeksi string yang di-encode. Jika mengandung karakter + atau / dan diakhiri dengan =, gunakan StdEncoding. Jika menggunakan karakter - dan _ tanpa =, gunakan RawURLEncoding. Bila tidak yakin, coba RawURLEncoding terlebih dahulu โ sebagian besar API modern (OAuth2, JWT, Google Cloud, AWS) menggunakan Base64 URL-safe tanpa padding.
package main
import (
"encoding/base64"
"strings"
)
// Detect encoding variant from the encoded string
func decodeAPIPayload(encoded string) ([]byte, error) {
// URL-safe characters without padding โ common in modern APIs
if !strings.Contains(encoded, "+") && !strings.Contains(encoded, "/") {
return base64.RawURLEncoding.DecodeString(encoded)
}
// Standard Base64 with padding
return base64.StdEncoding.DecodeString(encoded)
}Alat Terkait
- Enkoder Base64 โ encode data biner atau teks ke Base64 di browser, berguna untuk membuat fixture pengujian yang bisa langsung ditempel ke unit test Go Anda.
- Dekoder JWT โ pisahkan dan decode ketiga segmen JWT sekaligus, dengan inspeksi payload field per field โ tidak perlu kode Go saat Anda hanya perlu membaca token selama debugging.
- Dekoder URL โ percent-decode string yang di-encode URL, berguna saat respons API mencampur data Base64url dengan parameter query yang di-encode persen.
- Pemformat JSON โ setelah men-decode payload JWT Base64 atau respons API, tempel JSON-nya di sini untuk mencetak dan memvalidasi strukturnya secara instan.