A detailed backend reference

Serialisasi, bahasa bersama mesin-mesin.

Klien JavaScript dan server Rust tidak punya kesamaan apa pun di level tipe data. Serialisasi adalah cara mereka tetap bicara: keduanya mengonversi data natifnya ke dan dari satu format yang disepakati untuk perjalanan lewat jaringan. Manual ini mencakup seluruh gagasannya, hambatan bahasa, standar bersama, format teks vs biner, JSON secara mendalam, model mental OSI, dan round-trip penuh klien<->server, dengan kode jadi di Go dan Python.

native data <-> common format language-agnostic JSON / ~80% 11 sections Versi Sederhana
Part I, The ProblemWhy this exists
01

Hambatan Bahasa

Aplikasi web yang khas adalah dua mesin di tempat berbeda, terhubung lewat internet. Klien: frontend-nya, sering aplikasi JavaScript (React, Angular, Vue) yang berjalan di browser seperti Chrome, bicara ke server, backend-nya, yang mungkin berjalan di localhost atau di tempat jauh di AWS, GCP, atau Azure. Mereka berkomunikasi lewat protokol jaringan: HTTP (REST API tradisional), gRPC, atau WebSocket. Manual ini berasumsi HTTP/REST, karena itu yang masih paling umum.

Inilah jebakannya. Klien bisa jadi JavaScript dan server bisa jadi Rust, dan kedua bahasa itu memperlakukan data dengan cara yang sangat berbeda:

  • JavaScript dinamis dan tidak dikompilasi, tipe-nya longgar dan diputuskan saat runtime.
  • Rust dikompilasi dan sangat ketat soal tipe.

Jadi saat klien JavaScript mengirim objek seperti { name: "..." } di body request, server Rust tidak bisa memahami secara natif struktur data JavaScript, tipe datanya sendiri tidak mirip sama sekali dengan milik JavaScript. Masalah yang sama terjadi terbalik untuk respons. Dua mesin, dua dunia internal yang tak kompatibel, satu kabel di antara keduanya.

CLIENT / JavaScript dynamic / not compiled { name : "Ada" } SERVER / Rust compiled / strict types struct User { name : String } ? incompatible data types
The barrier. A Rust server can't natively parse a JavaScript object. They need a universal language for the trip across the network.
02

Serialize & Deserialize

Solusinya: kedua sisi menyepakati satu format standar yang umum untuk data di kabel. Setiap mesin mengonversi ke dalam format itu sebelum mengirim, dan keluar dari format itu setelah menerima.

Serialization

Mengonversi data natif (objek JavaScript, struct Rust, struct Go, objek Python) ke dalam format standar bersama sebelum mengirimnya lewat jaringan (atau menyimpannya).

Deserialization

Kebalikan persisnya: mengambil data dalam format bersama dan mem-parse-nya kembali ke tipe data natif mesin, supaya ia bisa menjalankan logika bisnisnya.

native data object / struct common format e.g. JSON text native data struct / object serialize -> -> deserialize
Two directions, one format. Serialize = native -> common. Deserialize = common -> native. The format in the middle is what travels.
Language-agnostic & domain-agnostic

Karena formatnya netral, mesin mana pun bisa bicara ke mesin mana pun apa pun bahasa atau teknologi di bawahnya. "Language-agnostic" berarti tidak peduli Anda JS atau Rust. "Domain-agnostic" berarti tidak peduli lingkungan atau tumpukan teknologi yang Anda jalankan.

Not only for the network

Gagasan konversi ke-dan-dari-format-bersama yang sama juga berlaku untuk penyimpanan: menulis data ke disk atau file config/log lalu membacanya kembali. Transmisi yang jadi fokus di sini, tapi fenomenanya sama.

Part II, The StandardsWhich format to agree on
03

Menyepakati Standar Bersama

Jika masalah ini diserahkan kepada Anda dalam keadaan dingin, dua mesin di lokasi berbeda, terhubung lewat internet, yang harus bertukar data secara language-agnostic, solusi yang jelas adalah mendefinisikan standar bersama.

A "standard" / "format"

Hanya istilah keren untuk sekumpulan aturan yang disepakati tentang cara data harus ditulis. Klien dan server sama-sama berjanji: "kami akan mengirim dan menerima data berbentuk seperti ini".

Dengan kesepakatan itu, klien mengonversi logika natifnya (misalnya dari JavaScript) ke dalam standar sebelum mengirim; server membaca standar itu dan mengonversinya ke tipe natifnya sendiri (misalnya struct Rust); ia bekerja, mengonversi respons kembali ke standar, dan mengirimnya; klien mem-parse-nya kembali ke JavaScript. Round-trip itu adalah serialisasi dan deserialisasi. Dalam satu kalimat: mengonversi data ke dan dari format bersama saat transmisi (atau penyimpanan), supaya bisa dipahami lintas bahasa dan domain.

04

Format Berbasis Teks vs Biner

Banyak sekali standar serialisasi, tapi mereka jatuh ke dua keluarga.

Serialization standards TEXT-BASED human-readable JSON YAML XML BINARY FORMAT compact / efficient / not human-readable Protobuf Avro
Two families. Text-based formats are readable by humans; binary formats compile to raw bytes for compact, efficient transmission.
  • Format berbasis teks: bisa dibaca manusia. JSON, YAML, dan XML. Anda bisa membuka payload-nya dan membacanya.
  • Format biner: dikompilasi menjadi biner mentah untuk transmisi yang sangat efisien dan ringkas. Protobuf (Protocol Buffers) dan Avro yang populer. Tidak dimaksudkan dibaca mata.

YAML dan XML masih dipakai untuk serialisasi, tapi tidak begitu sering untuk komunikasi HTTP. Untuk HTTP REST API tradisional, pilihan bawaan adalah JSON.

05

JSON: Standar Industri

Untuk komunikasi HTTP REST API tradisional, JSON adalah standar serialisasi paling populer, dipakai kira-kira 80% dari waktu.

JSON

JavaScript Object Notation. Dinamai begitu karena tampak dan berperilaku mirip objek JavaScript, tapi meski namanya begitu ia tidak terbatas pada JavaScript dan dipakai di mana-mana, di semua bahasa.

Kenapa ia menang

  • Bisa dibaca manusia. JSON dirancang untuk dibaca orang; Anda bisa melirik payload dan langsung mengerti. Itu salah satu daya jual terkuatnya.
  • Tipe data fundamental. Tipe nilainya memetakan dengan rapi ke konsep yang sudah diketahui setiap programmer.

Di mana Anda akan menjumpainya

  • Transmisi HTTP: body request/response REST API (fokus di sini).
  • Logging: pilihan yang sangat populer untuk log aplikasi dan server saat runtime.
  • File konfigurasi: config aplikasi dan tool.
06

Aturan Sintaks JSON

JSON punya sangat sedikit aturan, itulah intinya. Ini contoh objek khas, dengan anotasi untuk setiap aturan yang disebut sumber:

{ "name" : "Ada" , "age" : 30 , "active" : true , "tags" : [ "a" , "b" ], "address" : { "country" : "India" , "phone" : 123456 } opening brace { key, string, in double quotes values: string, number, boolean, array ... ... or a NESTED object (same rules) closing brace }
Every rule in one object. Braces wrap it; keys are quoted strings; values are simple types or nested objects.

Aturannya, dijabarkan

  • Objek JSON dimulai { dan diakhiri }.
  • Key harus string yang dibungkus tanda kutip ganda: mis. "name":. Tidak ada tipe data lain yang bisa jadi key. (Kutip ganda, selalu, bukan kutip tunggal.)
  • Nilai terbatas pada tipe fundamental: string, angka, boolean, larik, atau objek bertingkat lain.
  • Objek bertingkat mengikuti aturan yang sama persis secara rekursif: kurung kurawal, key string berkutip, dan nilai bertipe fundamental yang sama. JSON bisa menyarang sedalam yang Anda suka.
That's the whole spec, basically

Tidak banyak lagi yang perlu dihafal. Kurung kurawal membungkus objek, key string berkutip ganda, dan nilai berupa string, angka, boolean, larik, atau objek bertingkat, tiap objek bertingkat menaati karakteristik yang sama. Itu saja isi JSON.

Part III, Under the HoodWhat to ignore, and what not to
07

Model Mental OSI

Saat data melintasi internet ia melewati banyak lapisan jaringan, model OSI. Anda tidak perlu menguasai paket IP dan frame data untuk jadi engineer backend; gambaran tingkat tinggi cukup. Dua ujung tumpukan adalah lapisan aplikasi (atas) dan lapisan fisik (bawah); ada beberapa lapisan di antaranya, dan tumpukan yang sama ada di klien dan server.

CLIENT Application, JSON you live here ...transport / network... data frames / IP packets Physical, bits 0 1 0 1 0 1 SERVER Application, JSON you live here too ...transport / network... data frames / IP packets Physical, bits 0 1 0 1 0 1 the wire, electrical / optical signals carrying 0s and 1s JSON -> bits bits -> JSON
The abstraction. Your data starts and ends as JSON at the application layer. In between it becomes frames, packets, and bits, but that is not your concern.
The backend engineer's mental model

Anda hanya fokus pada lapisan aplikasi. Anggap klien Anda men-serialize data ke JSON lalu mengirimnya. Di balik layar jaringan mengubah JSON itu menjadi frame data -> paket IP -> bit fisik (0 dan 1) yang dikirim sebagai sinyal listrik atau optik. Sebelum server Anda menyentuh data, jaringan merakit ulang bit-bit itu menjadi JSON yang sama persis dengan yang dikirim klien. Anda tidak pernah berurusan dengan konversi perantara, hanya JSON-nya.

08

Alur Kerja End-to-End

Merangkai setiap bagian, inilah round-trip lengkap dalam request sungguhan, fenomena yang secara utuh adalah serialisasi & deserialisasi.

CLIENT (JavaScript) 1 / gather user input 2 / SERIALIZE -> JSON attach to HTTP body 3 / TRANSMIT JSON -> bits -> across the internet SERVER (Rust) 4 / DESERIALIZE JSON -> Rust struct 5 / PROCESS / save to DB 6 / SERIALIZE -> JSON the HTTP response transmit back JSON -> bits -> across the internet 7 / DESERIALIZE JSON -> JS object update the UI
The full round-trip. Serialize on each side before sending; deserialize on each side after receiving. Four conversions per request/response cycle.

Dalam kata-kata: klien mengumpulkan input, men-serialize-nya menjadi string JSON di body request, lalu mengirimkannya; bit-bit melintasi internet; server men-deserialize JSON menjadi tipe natifnya, menjalankan logika bisnis (mis. menyimpan ke database), men-serialize responsnya kembali ke JSON, dan mengirimnya; klien men-deserialize JSON itu menjadi objek JavaScript dan memperbarui UI. Seluruh alur itulah yang kita sebut serialisasi dan deserialisasi, fenomena yang sebagian besar cukup Anda ketahui keberadaannya; ia punya sangat sedikit konsep sendiri.

Part IV, ImplementationSerialize for real, with the OOP showing
09

Serialisasi di Go

Go men-serialize ke/dari JSON dengan paket standar encoding/json: Marshal = serialize, Unmarshal = deserialize. Pilar-pilarnya muncul lewat interface (abstraksi + polimorfisme), field tak-terekspor + struct tag (enkapsulasi), dan embedding (komposisi, inheritance ala Go). Pilar ditandai tag OOP.

Go 1.22+serialize.go
package main

import ("encoding/json"; "fmt"; "time")

// ABSTRACTION: Serializer names a capability, "turn data into
// bytes and back", without binding to a concrete format. Code
// depends on this contract, so JSON could be swapped for another
// format with zero changes to callers.
type Serializer interface {
    Serialize(v any) ([]byte, error)   // native -> common format
    Deserialize(data []byte, v any) error // common format -> native
}

// POLYMORPHISM: JSONSerializer implements Serializer. Any other
// format (YAML, Protobuf) could implement the same interface and
// be used interchangeably through a Serializer variable.
type JSONSerializer struct{}

func (JSONSerializer) Serialize(v any) ([]byte, error) {
    return json.Marshal(v)   // SERIALIZE: struct -> JSON bytes
}
func (JSONSerializer) Deserialize(data []byte, v any) error {
    return json.Unmarshal(data, v) // DESERIALIZE: JSON bytes -> struct
}

// "INHERITANCE" via COMPOSITION: BaseModel holds shared fields;
// embedding it into User reuses them (and their json tags).
type BaseModel struct {
    ID        int       `json:"id"`         // tag = the JSON key name
    CreatedAt time.Time `json:"created_at"`
}

// ENCAPSULATION: an exported struct whose JSON shape is controlled
// by tags. "password" is unexported (lowercase) -> private AND
// invisible to the JSON encoder, so it never leaks over the wire.
type User struct {
    BaseModel            // embedded -> inherits ID, CreatedAt
    Name    string      `json:"name"`
    Active  bool        `json:"active"`
    Address Address     `json:"address"` // nested object
    password string     // unexported: hidden from JSON output
}

type Address struct {
    Country string `json:"country"`
    Phone   int    `json:"phone"`
}

func main() {
    var codec Serializer = JSONSerializer{} // program to the interface

    u := User{
        BaseModel: BaseModel{ID: 1, CreatedAt: time.Now()},
        Name:      "Ada", Active: true,
        Address:   Address{Country: "India", Phone: 123456},
    }

    // SERIALIZE, native Go struct into the common JSON format
    out, _ := codec.Serialize(u)
    fmt.Println(string(out))
    // {"id":1,"created_at":"...","name":"Ada","active":true,
    //  "address":{"country":"India","phone":123456}}

    // DESERIALIZE, JSON received over HTTP back into a Go struct
    incoming := []byte(`{"name":"Lin","address":{"country":"IN","phone":42}}`)
    var back User
    codec.Deserialize(incoming, &back)
    fmt.Println(back.Name, back.Address.Country) // Lin IN
}
10

Serialisasi di Python

Python memakai modul json bawaan: json.dumps = serialize (dump ke string), json.loads = deserialize (load dari string). Arsitektur OOP yang sama: kontrak ABC, inheritance, polimorfisme, dan atribut privat.

Python 3.11+serialize.py
import json
from abc import ABC, abstractmethod
from dataclasses import dataclass, asdict, field

# ABSTRACTION: Serializer is an Abstract Base Class. The
# @abstractmethod forces subclasses to implement both directions.
# You cannot instantiate Serializer itself, it is a pure contract.
class Serializer(ABC):
    @abstractmethod
    def serialize(self, obj) -> str: ...      # native -> common
    @abstractmethod
    def deserialize(self, data: str): ...      # common -> native

# INHERITANCE + POLYMORPHISM: JSONSerializer IS-A Serializer and
# overrides both methods. A YamlSerializer could subclass the same
# ABC and be dropped in wherever a Serializer is expected.
class JSONSerializer(Serializer):
    def serialize(self, obj) -> str:
        return json.dumps(obj)               # SERIALIZE: dict -> JSON text
    def deserialize(self, data: str):
        return json.loads(data)              # DESERIALIZE: JSON text -> dict

# INHERITANCE: BaseModel is a shared parent (id, timestamps).
@dataclass
class BaseModel:
    id: int = 0

@dataclass
class Address:
    country: str
    phone: int                              # nested object

# ENCAPSULATION: __password is name-mangled (-> _User__password),
# effectively private, and to_dict() chooses what leaves the
# object, the secret never appears in the serialized output.
@dataclass
class User(BaseModel):                     # IS-A BaseModel
    name: str = ""
    active: bool = True
    address: Address | None = None
    __password: str = ""                  # private; excluded below

    def to_dict(self) -> dict:
        d = asdict(self)
        d.pop("_User__password", None)        # keep the secret out
        return d

if __name__ == "__main__":
    codec: Serializer = JSONSerializer()    # program to the contract

    user = User(id=1, name="Ada",
                address=Address("India", 123456))

    # SERIALIZE, native object into the common JSON format
    payload = codec.serialize(user.to_dict())
    print(payload)
    # {"id": 1, "name": "Ada", "active": true,
    #  "address": {"country": "India", "phone": 123456}}

    # DESERIALIZE, JSON received over HTTP back into native data
    incoming = '{"name": "Lin", "address": {"country": "IN", "phone": 42}}'
    data = codec.deserialize(incoming)
    print(data["name"], data["address"]["country"])  # Lin IN
Same shape, two languages

Keduanya mendefinisikan kontrak Serializer (abstraksi), mengimplementasikannya untuk JSON (polimorfisme), berbagi field lewat base model (inheritance / komposisi), dan menjaga rahasia keluar dari format kabel (enkapsulasi). Kata kerjanya universal: serialize = natif -> JSON (Go Marshal, Python dumps); deserialize = JSON -> natif (Go Unmarshal, Python loads).

11

Glosarium

Setiap istilah dari sumber, dalam satu tempat.

IstilahMakna
SerializationMengonversi data natif (objek/struct) ke format standar bersama untuk dikirim atau disimpan.
DeserializationKebalikannya, mem-parse format bersama kembali ke tipe data natif mesin.
Klien / frontendAplikasi yang mengirim request, sering aplikasi JavaScript di browser.
Server / backendMesin yang menerima request dan menjalankan logika bisnis (mis. aplikasi Rust).
Tipe data natifRepresentasi internal milik sebuah bahasa, objek JS, struct Rust/Go, objek Python.
ParseMembaca sebuah format dan mengubahnya menjadi sesuatu yang bisa dipakai mesin.
Standar / format bersamaSekumpulan aturan yang disepakati untuk cara data ditulis, supaya kedua sisi memahaminya.
Language-agnosticBerfungsi apa pun bahasa pemrograman yang dipakai tiap sisi.
Domain-agnosticBerfungsi apa pun lingkungan / tumpukan teknologi di tiap sisi.
Format berbasis teksSerialisasi yang bisa dibaca manusia, JSON, YAML, XML.
Format binerSerialisasi yang ringkas, efisien, tak terbaca, Protobuf, Avro.
JSONJavaScript Object Notation; pilihan ±80% untuk HTTP REST; bisa dibaca manusia; bukan khusus JS.
Key / valueKey JSON berupa string berkutip; nilai berupa string, angka, boolean, larik, atau objek bertingkat.
Objek bertingkatObjek JSON di dalam objek lain, mengikuti aturan yang sama secara rekursif.
Model OSIModel berlapis komunikasi jaringan, dari lapisan aplikasi sampai lapisan fisik.
Lapisan aplikasiLapisan teratas, tempat Anda, engineer backend, bekerja dalam JSON.
Lapisan fisikLapisan terbawah, bit mentah (0 dan 1) sebagai sinyal listrik/optik.
Frame data / paket IPBentuk antara yang diambil data antara lapisan aplikasi dan fisik.
The whole idea in one breath

Dua mesin dengan tipe data natif yang tidak kompatibel menyepakati format bersama (biasanya JSON). Masing-masing men-serialize datanya ke format itu sebelum mengirim dan men-deserialize-nya kembali setelah menerima, jadi komunikasi jadi language- dan domain-agnostic. Jaringan mengubah JSON menjadi bit dan kembali; di lapisan aplikasi Anda hanya berurusan dengan JSON.