Web service API server
Bangun endpoint yang menyajikan JSON.
Pahami konsepnya
API server adalah web server yang jalannya sama dengan JSON: handler menerima permintaan, memprosesnya, dan membalas body JSON dengan status serta header yang tepat. Kerangkanya: atur w.Header().Set("Content-Type", "application/json"), marshal data, w.Write(keluaran).
r.Method memisahkan GET dan POST pada rute yang sama — pola REST dasar. POST membaca body lewat json.NewDecoder(r.Body).Decode(&masukan), mengisi struct dari JSON kiriman klien. Kesalahan (bad request, data tak ditemukan) diwakili status code: w.WriteHeader(http.StatusBadRequest) sebelum menulis body error dalam bentuk JSON juga.
Berkas utama server nyata biasanya memisahkan handler per entitas dan mendaftarkan banyak rute; kerangkanya tetap persis tiga langkah ini: header → status → body. Uji dengan curl: curl localhost:8080/api/siswa dan curl -X POST -d '{"nama":"Citra"}' localhost:8080/api/siswa.
Coba contoh kode
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Siswa struct {
Nama string `json:"nama"`
Poin int `json:"poin"`
}
var siswa = []Siswa{{Nama: "Ari", Poin: 95}}
func main() {
http.HandleFunc("/api/siswa", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(siswa)
case http.MethodPost:
var baru Siswa
if err := json.NewDecoder(r.Body).Decode(&baru); err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, `{"error":"json tidak valid"}`)
return
}
siswa = append(siswa, baru)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(baru)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
})
http.ListenAndServe(":8080", nil)
}Satu rute, dua perilaku: GET mengembalikan daftar siswa sebagai JSON (NewEncoder menulis langsung ke response), POST menambahkan siswa baru dan menjawab 201 Created. Body yang bukan JSON valid ditolak 400 dengan pesan error JSON. json.NewEncoder(w) menggabungkan marshal+tulis dalam satu langkah.
Parameter path dan 404
http.HandleFunc("/api/siswa/", func(w http.ResponseWriter, r *http.Request) {
nama := strings.TrimPrefix(r.URL.Path, "/api/siswa/")
for _, s := range siswa {
if s.Nama == nama {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(s)
return
}
}
w.WriteHeader(http.StatusNotFound)
})Rute dengan akhiran "/" menangkap semua sub-pathnya; potongan setelah prefix diambil dengan TrimPrefix sebagai identitas. Tak ketemu → 404. (Sejak Go 1.22 ada r.PathValue("nama") dengan pola "/api/siswa/{nama}" yang jauh lebih bersih — bentuk manual ini menunjukkan mesin di baliknya.)