Episode ini membangun HTTP server pertama di Rust dengan axum, membahas request-response, routing, middleware, dan error handling, lalu mengenal koneksi TCP dan UDP dasar serta konsep service discovery untuk aplikasi terdistribusi.

Setelah menguasai data dan konfigurasi, saatnya aplikasi Rust kalian berbicara dengan dunia luar. Episode 10 adalah titik di mana program kalian berubah menjadi service nyata: menerima request HTTP, memprosesnya, dan mengembalikan respons.
Kita mulai dari dasar jaringan dengan std::net, lalu membangun HTTP server dengan axum — framework modern di atas hyper. Kalian akan belajar routing, middleware, error handling, serta melihat sekilas warp, actix-web, dan konsep service discovery. Di akhir episode, kalian punya API yang bisa diuji dengan curl.
Sebelum HTTP, pahami transport-nya: TCP menyediakan koneksi andal berurutan, UDP menyediakan datagram cepat tanpa jaminan. Standard library menyediakan keduanya:
cat > src/main.rs <<'EOF'
use std::io::{Read, Write};
use std::net::TcpListener;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8000").unwrap();
println!("mendengarkan di 127.0.0.1:8000");
for stream in listener.incoming() {
let mut stream = stream.unwrap();
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
let respons = b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok";
stream.write_all(respons).unwrap();
}
}
EOF
cargo runTcpListener::bind("127.0.0.1:8000") membuka port lokal, dan listener.incoming() menghasilkan koneksi masuk. Contoh di atas bahkan sudah merespons HTTP — meskipun sangat primitif. cargo run lalu uji dengan curl http://127.0.0.1:8000 dari terminal lain.
UDP dipakai untuk DNS, telemetri, dan game karena overheadnya minimal. Di Rust, UdpSocket::bind dan send_to/recv_from menangani datagram. Untuk HTTP dan service bisnis, TCP tetap pilihan utama.
axum dibangun di atas hyper dan tower, memakai arsitektur handler dan extractor yang ekspresif. Tambahkan dependency dengan cargo add axum tokio --features tokio/full:
cat > src/main.rs <<'EOF'
use axum::{routing::get, Router};
async fn halo() -> &'static str {
"Halo dari axum"
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(halo));
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
println!("listening on 127.0.0.1:3000");
axum::serve(listener, app).await.unwrap();
}
EOF
cargo runRouter::new().route("/", get(halo)) mendaftarkan handler ke path. axum::serve menjalankan server async. Uji dengan curl http://127.0.0.1:3000 dan kalian akan melihat respons Halo dari axum.
Handler menerima extractor seperti Path, Query, Json, dan State, serta mengembalikan tipe apa pun yang mengimplementasi IntoResponse:
cat > src/main.rs <<'EOF'
use axum::{extract::Path, routing::get, Json, Router};
use serde::Serialize;
#[derive(Serialize)]
struct Pengguna {
id: u32,
nama: String,
}
async fn detail(Path(id): Path<u32>) -> Json<Pengguna> {
Json(Pengguna {
id,
nama: format!("pengguna {}", id),
})
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/api/pengguna/{id}", get(detail));
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
EOF
cargo runPath(id): Path<u32> mengambil nilai dari segmen {id}. Json<Pengguna> membuat respons JSON dari struct ber-Serialize. Uji dengan curl http://127.0.0.1:3000/api/pengguna/7.
Middleware menangani concern lintas request: logging, timeout, CORS, dan kompresi. axum memakai lapisan dari tower:
use tower_http::trace::TraceLayer;
let app = Router::new()
.route("/", get(|| async { "selamat datang" }))
.layer(TraceLayer::new_for_http())
.fallback(|| async { (StatusCode::NOT_FOUND, "tidak ditemukan") });TraceLayer mencatat setiap request beserta status dan durasi. fallback menangani path yang tidak terdaftar. Layer dipasang dengan .layer(...) dan diterapkan dari luar ke dalam.
Handler mengembalikan Result<T, E> di mana E: IntoResponse:
struct AppError(anyhow::Error);
impl IntoResponse for AppError {
fn into_response(self) -> Response {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("terjadi kesalahan: {}", self.0),
)
}
}
async fn index() -> Result<&'static str, AppError> {
Ok("api sehat")
}Error dari handler dikonversi menjadi respons HTTP dengan status yang sesuai. Operator ? di dalam handler mempropagasi error internal, dan AppError mengubahnya menjadi respons yang ramah klien.
Selain axum: warp memakai filter combinators yang komposable, actix-web menawarkan model aktor dan performa tinggi, sedangkan hyper adalah fondasi HTTP rendah yang dipakai axum sendiri. Pilih axum untuk ekosistem tokio, actix-web untuk tim yang ingin framework semua-dalam-satu, dan warp untuk gaya fungsional.
Di lingkungan terdistribusi, instance service tidak saling tahu alamatnya. Service discovery menyelesaikan ini: instance mendaftarkan diri ke registry (misalnya etcd, Consul, atau registry bawaan Kubernetes), dan konsumen menanyakan registry untuk menemukan alamat aktif. Di Rust, crate seperti rust-consul dan tonic (untuk gRPC) menjadi jembatan menuju ekosistem ini.
Inti yang harus dibawa pulang:
std::net menyediakan TCP dan UDP dasar; TCP untuk layanan andal.Path, Query, dan Json membentuk API.Di episode 11 selanjutnya kita akan membahas keamanan, TLS, dan auth — mengaktifkan HTTPS dengan TLS dan sertifikat, implementasi autentikasi JWT, OAuth2, dan session, serta proteksi input, CORS, rate limiting, dan security header. API kalian siap dihadirkan ke publik.