← Kembali ke kursus
Pelajaran kursus · Go
Pelajaran 49

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.)