Go HTTP Server Routing Middleware JSON API
Selesai membaca dokumentasi ini?
Kembali ke rujukan utama Go (Golang) untuk melanjutkan topik lainnya.
Kembali ke rujukan utama Go (Golang) untuk melanjutkan topik lainnya.
net/http adalah paket standar Go untuk membuat HTTP server dan HTTP client. Untuk sisi server, paket ini memberi fondasi yang cukup lengkap untuk menerima request, membaca body, menulis response, dan mengatur routing sederhana tanpa dependency tambahan.
Kalau dipakai di project kecil atau API internal, net/http sering sudah cukup. Kamu baru butuh router atau middleware tambahan kalau kebutuhan routing mulai kompleks, ada banyak cross-cutting concern, atau struktur handler mulai sulit dirawat.
net/http bekerjaDi sisi server, alurnya sederhana:
net/http membuat *http.Requesthttp.ResponseWriterYang penting dipahami: di Go, HTTP server tidak bergantung pada framework besar untuk bisa berjalan. Yang benar-benar dibutuhkan adalah handler yang memenuhi interface berikut:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Artinya, setiap tipe yang punya method ServeHTTP(http.ResponseWriter, *http.Request) bisa dipakai sebagai handler.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/health", func(w http.ResponseWriter, r *http
Kalau ListenAndServe diberi nil, Go memakai http.DefaultServeMux sebagai router default.
Routing adalah proses mencocokkan request path dan method ke handler yang tepat.
http.HandleFunc dan DefaultServeMuxCocok untuk:
Kelemahannya:
http.NewServeMuxIni pilihan yang lebih rapi daripada memakai default global.
mux := http.NewServeMux()
mux.HandleFunc("/health", healthHandler)
mux.HandleFunc("/users", usersHandler)
http.ListenAndServe(":8080", mux)Pakai NewServeMux kalau kamu ingin:
ServeMux hanya cocokkan path, bukan method. Jadi kalau endpoint yang sama harus beda perilaku untuk GET, POST, atau DELETE, method check harus dilakukan di handler atau lewat wrapper.
func usersHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
w.Write([]byte("list users"))
case http.MethodPost:
w.
Kamu mulai butuh router sendiri atau framework/router tambahan kalau:
/users/{id}Kalau masih bisa dibaca jelas dengan ServeMux, jangan buru-buru nambah abstraksi.
Urutan ini penting karena middleware biasanya dipakai untuk hal yang sifatnya lintas handler, misalnya:
Kamu tidak harus menulis tipe handler sendiri untuk semua hal. http.HandlerFunc sudah cukup untuk banyak kasus.
HandlerFunc kalauContoh:
type UserHandler struct {
Logger *log.Logger
}
func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Logger.Println
Pola ini membantu kalau project mulai membesar. Handlermu tetap kecil, dependency-nya jelas, dan testing lebih mudah.
Middleware adalah fungsi yang membungkus handler lain. Tujuannya bukan mengganti business logic, tapi menambahkan perilaku sebelum atau sesudah handler.
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// sebelum handler
next.
Middleware cocok untuk logic yang:
Contoh paling umum:
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start :=
Middleware bisa ditumpuk.
handler := Logging(Auth(mux))Urutan penting. Kalau auth harus terjadi sebelum handler, middleware auth harus ada di lapisan yang tepat.
JSON API biasanya menerima payload lewat request body. Di Go, parsing JSON paling umum memakai encoding/json.
Content-Type kalau perlutype CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
}func createUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err !=
Decode membaca dari body stream, bukan dari string yang sudah ditampung penuhIni penting supaya server kecil tidak gampang dipaksa membaca payload besar.
r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MBUntuk response JSON, pakai json.NewEncoder(w).Encode(...) supaya format konsisten.
type ErrorResponse struct {
Error string `json:"error"`
}
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json"
type UserResponse struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
writeJSON(w, http.StatusCreated, UserResponse{
ID: 1,
Name: req.Name,
Email: req.Email,
})Helper kecil seperti ini mengurangi duplikasi dan menjaga perilaku response tetap konsisten:
Content-Typepackage main
import (
"encoding/json"
"log"
http.DefaultServeMux tanpa sadarKalau handler didaftarkan ke fungsi global seperti http.HandleFunc, state routing jadi global. Ini bisa bikin testing dan struktur package berantakan.
Lebih aman gunakan http.NewServeMux() lalu inject ke http.Server.
ServeMux tidak membedakan GET dan POST. Kalau endpoint harus method-specific, cek sendiri atau pakai router yang mendukung method routing.
Content-TypeClient bisa salah mengira response adalah plain text. Set header sebelum encode.
Kalau request body tidak dibatasi, server kecil bisa lebih mudah kena payload besar atau abuse.
json.DecodeKalau decode gagal dan handler tetap lanjut, data request bisa setengah terisi. Selalu fail fast.
Di banyak contoh sederhana, error Encode sering diabaikan. Di service kecil ini kadang lolos, tapi di production tetap perlu dipikirkan.
Tanpa middleware recovery, satu panic bisa menutup request dan mencemari log. Minimal punya middleware recovery kalau server mulai dipakai serius.
Handler sebaiknya tipis. Kalau logic terlalu tebal, pindahkan ke service layer supaya mudah dites dan diubah.
json:"user_name" dan json:"username" terlihat sepele, tapi bisa bikin payload tidak cocok dengan kontrak API.
Server tanpa timeout lebih rentan terhadap koneksi lambat atau request yang menggantung.
srv := &http.Server{
Addr: ":8080",
Handler: handler,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
net/http saja sudah cukupPakai net/http saja kalau:
Tambahkan router/middleware library kalau kebutuhan berikut mulai muncul:
Kalau bingung, pakai urutan keputusan ini:
ServeMux?Kalau jawaban pertanyaan itu jelas, implementasi Go biasanya akan ikut jelas juga.
net/http memberi fondasi server HTTP yang cukup kuat tanpa framework besar.ServeMux cukup untuk routing sederhana, tapi method check tetap perlu ditangani.json.Decoder, JSON response ditulis dengan json.Encoder.Kalau kamu butuh, pola dasar ini bisa jadi fondasi yang bersih sebelum naik ke router yang lebih lengkap.