Client-server adalah arsitektur paling fundamental di web. Client (browser/app) mengirim request, server memproses dan mengirim response.
Evolusi arsitektur web:
1. Monolith — semua dalam satu
┌─────────────────────┐
│ Server │
│ ┌─────┐ ┌────────┐ │
│ │ UI │ │ Logic │ │
│ │(SSR)│ │(Routes)│ │
│ └─────┘ └────────┘ │
│ ┌────────────────┐ │
│ │ Database │ │
│ └────────────────┘ │
└─────────────────────┘
Kelebihan: sederhana, mudah deploy, satu codebase Kekurangan: sulit scale, satu bug bisa matikan semuanya
2. Client-Server Terpisah (SPA + API)
┌──────────┐ HTTP/JSON ┌──────────┐
│ Client │ ◄────────────► │ Server │
│ (React) │ │ (Laravel)│
│ (SPA) │ │ (API) │
└──────────┘ └──────────┘
│
┌────┴────┐
│Database │
└─────────┘
Kelebihan: bisa scale terpisah, team terpisah, bisa punya mobile app Kekurangan: lebih kompleks, CORS, state management
3. Multi-tier Architecture
┌────────┐ ┌───────────┐ ┌──────────┐ ┌──────────┐
│ Client │ → │ Web Server│ → │ App │ → │ Database │
│ │ │ (Nginx) │ │ Server │ │ (MySQL) │
└────────┘ └───────────┘ └──────────┘ └──────────┘
Tier 1 Tier 2 Tier 3 Tier 4
Komunikasi Client-Server:
REST API — standar paling umum:
// Client mengirim request
const response = await fetch("https://api.example.com/articles", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Belajar System Design" })
});
// Server mengembalikan response
// HTTP 201 Created
// { "id": 42, "title": "Belajar System Design", "created_at": "..." }
GraphQL — query apa yang dibutuhkan:
query {
user(id: 42) {
name
articles { title, created_at }
}
}
gRPC — performa tinggi, binary protocol: Dipakai untuk komunikasi antar microservices. Lebih cepat dari REST/JSON karena menggunakan Protocol Buffers (binary).
Stateless vs Stateful:
- Stateless — server tidak menyimpan state client antar request. Setiap request membawa semua info yang diperlukan (token, dll). Lebih mudah di-scale.
- Stateful — server mengingat state client (misalnya session). Lebih sulit di-scale karena request harus selalu ke server yang sama.
Best practice: Buat server stateless sebisa mungkin. Simpan state di database atau cache (Redis) yang bisa di-share antar server.
Reverse Proxy: Server perantara yang menerima request dari client dan meneruskan ke backend server yang tepat. Fungsinya: load balancing, SSL termination, caching, security.
Client → Nginx (reverse proxy) → App Server 1
→ App Server 2
→ App Server 3
🎭 Analogi sehari-hari: Restoran. Client = pelanggan, Server = dapur. Pelanggan order ke kasir (request), kasir kirim ke dapur, dapur masak, makanan kembali ke pelanggan (response). Multi-tier: pelanggan → kasir (load balancer) → koki spesialis (app server) → gudang bahan (database). Setiap tier independent, masing-masing bisa diganti tanpa rusak yang lain.
💡 Stateless = scalability winner: Server stateless = setiap request self-contained (token JWT, ID di header, dll). User datang ke server manapun, dapet hasil sama. Stateful = "kamu punya session di server A, harus ke A terus". Kalau A mati = data hilang. Stateful bikin scaling horizontal mimpi buruk.
⚠️ Jebakan umum:
- CORS bingung saat split client+server beda domain — wajib config CORS di backend
- API versioning lupa —
/v1/usersvs/v2/users. Tanpa versioning, breaking change = bencana - Stateful session di server = scaling rusak. Pakai Redis atau JWT
- Reverse proxy lupa SSL termination — cert expire = downtime
- Mix REST + GraphQL + gRPC tanpa alasan — pilih yang fit
🎯 REST vs GraphQL vs gRPC:
- REST: standar, simple, cocok 80% kasus, cache friendly
- GraphQL: client butuh data flexible, hindari over/under-fetching, cocok mobile
- gRPC: internal microservice, performa tinggi, binary, type-safe
TL;DR: Client-server = pondasi web. Stateless server = scaling-friendly. Multi-tier = setiap layer independent. Pilih protocol (REST/GraphQL/gRPC) sesuai use case. Reverse proxy untuk LB, SSL, security.