Kodeloka
  1. Kodeloka
  2. Kelas Golang
  3. Materi

Domain 20 · 23 bab

Golang Web Development

201. Arsitektur Web (Client & Server) & Package net/http

Konsep dasar HTTP Protocol, Client-Server architecture, dan pengenalan package net/http.

Arsitektur Web di Golang

Golang memiliki pendirian "Batteries Included" untuk pengembangan web. Package standar net/http menyediakan HTTP Server & Client kelas produksi tanpa memerlukan framework pihak ketiga.

KomponenPeran di Go
Client (Browser/Postman)Mengirim HTTP Request ke Server
http.ServerMendengarkan Port TCP & menerima koneksi HTTP
http.HandlerMemproses request dan menulis HTTP Response

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("=== NET/HTTP PACKAGE ===")
	fmt.Println("Golang memiliki Web Server bawaan yang sangat kencang di package net/http.")
	_ = http.Server{}
}

Praktik dan kuis bab ini di kelas interaktif →

202. HTTP Server & http.ListenAndServe

Menjalankan HTTP Web Server lokal dengan mengonfigurasi host dan port.

Menjalankan HTTP Server

Fungsi http.ListenAndServe("localhost:8080", handler) digunakan untuk menyalakan web server pada address tertentu.

server := http.Server{
    Addr: "localhost:8080",
    Handler: mux,
}
err := server.ListenAndServe()

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	server := &http.Server{
		Addr: "localhost:8080",
	}
	fmt.Println("Server siap berjalan pada address:", server.Addr)
}

Praktik dan kuis bab ini di kelas interaktif →

203. Handler & http.HandlerFunc

Membuat fungsi pemroses request HTTP menggunakan interface http.Handler dan adapter HandlerFunc.

Interface http.Handler

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Kita dapat mengubah fungsi biasa menjadi `http.Handler` menggunakan adapter `http.HandlerFunc`:

var handler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello Golang Web!")
}

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	var handler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Halo Pengunjung Web Go!")
	}
	fmt.Println("HandlerFunc berhasil dikonfigurasi:", handler != nil)
}

Praktik dan kuis bab ini di kelas interaktif →

204. Multi-Routing dengan http.ServeMux

Mengarahkan berbagai endpoint URL ke handler yang sesuai menggunakan ServeMux.

Pengenalan http.ServeMux

http.ServeMux adalah HTTP request multiplexer bawaan Go. Mux mencocokkan URL dari setiap request yang masuk dengan daftar pola (pattern) yang didaftarkan.

mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
mux.HandleFunc("/about", aboutHandler)

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Index Page")
	})
	mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello Page")
	})
	fmt.Println("ServeMux siap dengan 2 endpoint (/ dan /hello).")
}

Praktik dan kuis bab ini di kelas interaktif →

205. Handling HTTP Request & Method Inspecting

Memeriksa detail informasi HTTP Request seperti Method (GET, POST), URL Path, dan Protocol.

Struktur *http.Request

Objek *http.Request menampung seluruh atribut request yang dikirim client:

  • r.Method: "GET", "POST", "PUT", "DELETE"
  • r.URL.Path: "/users/profile"
  • r.Header: Map header HTTP

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "/api/users", nil)
	fmt.Println("Method:", req.Method)
	fmt.Println("Path:", req.URL.Path)
}

Praktik dan kuis bab ini di kelas interaktif →

206. Testing Web Handler dengan Package httptest

Melakukan unit testing pada HTTP handler tanpa harus menyalakan server fisik di port TCP.

Package net/http/httptest

Go memiliki package khusus untuk menguji handler web secara instan:

req := httptest.NewRequest("GET", "/hello", nil)
recorder := httptest.NewRecorder()

HelloHandler(recorder, req)

res := recorder.Result()
fmt.Println("Status:", res.StatusCode)

Contoh program

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	handler := func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "OK Test")
	}

	req := httptest.NewRequest("GET", "/", nil)
	rec := httptest.NewRecorder()

	handler(rec, req)
	fmt.Println("Hasil Response Test Body:", rec.Body.String())
}

Praktik dan kuis bab ini di kelas interaktif →

207. Query Parameter & Multi-Value Query Params

Membaca data parameter dari URL query string (?name=Eko&age=30).

Membaca Query Parameter

Query parameter diambil dari `r.URL.Query()` yang mengembalikan tipe url.Values (map[string][]string):

name := r.URL.Query().Get("name") // Nilai pertama
tags := r.URL.Query()["tags"]     // Multi-values slice

Contoh program

package main

import (
	"fmt"
	"net/url"
)

func main() {
	u, _ := url.Parse("http://localhost:8080/search?q=golang&page=2&tags=go&tags=web")
	q := u.Query()

	fmt.Println("Keyword (q):", q.Get("q"))
	fmt.Println("Page:", q.Get("page"))
	fmt.Println("Tags (slice):", q["tags"])
}

Praktik dan kuis bab ini di kelas interaktif →

208. Reading & Writing HTTP Headers

Membaca header request dan menulis header response seperti Content-Type dan Custom Headers.

HTTP Headers

// Membaca Header Request
contentType := r.Header.Get("Content-Type")

// Menulis Header Response (Wajib sebelum WriteHeader/Write)
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Powered-By", "Golang")

Contoh program

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	handler := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, `{"message":"Hello JSON"}`)
	}

	rec := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/", nil)
	handler(rec, req)

	fmt.Println("Response Content-Type Header:", rec.Header().Get("Content-Type"))
}

Praktik dan kuis bab ini di kelas interaktif →

209. Parsing Form Post (URL Encoded & Form Data)

Membaca input data form dari request body POST.

Membaca Data POST Form

err := r.ParseForm()
firstName := r.PostFormValue("first_name")
email := r.PostForm.Get("email")
💡 Tips:

r.PostFormValue("key") otomatis memanggil r.ParseForm() jika belum dipanggil sebelumnya.

Contoh program

package main

import (
	"fmt"
	"net/http"
	"strings"
)

func main() {
	req, _ := http.NewRequest("POST", "/login", strings.NewReader("username=eko&password=secret123"))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	
	req.ParseForm()
	fmt.Println("Username:", req.PostFormValue("username"))
	fmt.Println("Password:", req.PostFormValue("password"))
}

Praktik dan kuis bab ini di kelas interaktif →

210. Setting HTTP Response Status Code (w.WriteHeader)

Mengirimkan HTTP status code spesifik (200 OK, 400 Bad Request, 404 Not Found, 500 Internal Error).

HTTP Response Code

w.WriteHeader(http.StatusNotFound) // 404
fmt.Fprintln(w, "Halaman Tidak Ditemukan")

Jika w.WriteHeader() tidak dipanggil eksplisit, Go secara otomatis mengirimkan 200 OK saat pertama kali w.Write() dipanggil.

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Konstanta Status Code Go:")
	fmt.Println("Status OK:", http.StatusOK)
	fmt.Println("Status Bad Request:", http.StatusBadRequest)
	fmt.Println("Status Not Found:", http.StatusNotFound)
	fmt.Println("Status Internal Error:", http.StatusInternalServerError)
}

Praktik dan kuis bab ini di kelas interaktif →

211. Managing HTTP Cookies (http.Cookie)

Membuat, mengirim, dan membaca Cookie pada web browser client.

Operasi Cookie

// Menulis Cookie
cookie := &http.Cookie{
    Name: "X-User-Token",
    Value: "abc123token",
    Path: "/",
}
http.SetCookie(w, cookie)

// Membaca Cookie
cookie, err := r.Cookie("X-User-Token")

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	c := &http.Cookie{
		Name:  "session_id",
		Value: "xyz987654",
		Path:  "/",
	}
	fmt.Printf("Cookie Struct: %s=%s (Path: %s)
", c.Name, c.Value, c.Path)
}

Praktik dan kuis bab ini di kelas interaktif →

212. Serving Static Files dengan http.FileServer & http.ServeFile

Menyajikan file statis (HTML, CSS, JS, Gambar) ke browser client.

Static File Server

directory := http.Dir("./static")
fileServer := http.FileServer(directory)

// Menghapus prefix URL sebelum meneruskan ke folder
mux.Handle("/static/", http.StripPrefix("/static", fileServer))

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	fs := http.FileServer(http.Dir("./static"))
	handler := http.StripPrefix("/assets", fs)
	fmt.Println("FileServer & StripPrefix terkonfigurasi:", handler != nil)
}

Praktik dan kuis bab ini di kelas interaktif →

213. HTML Templating Dasar (html/template)

Membuat tampilan HTML dinamis menggunakan package standar html/template.

Package html/template

tmpl, err := template.ParseFiles("./templates/index.gohtml")
tmpl.Execute(w, data)
💡 Kenapa html/template?

Package ini secara otomatis menangani escaping karakter HTML sehingga aman dari serangan XSS secara default.

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
)

func main() {
	text := "<h1>Selamat Datang, {{.}}!</h1>"
	tmpl, _ := template.New("index").Parse(text)

	var buf bytes.Buffer
	tmpl.Execute(&buf, "Budi Kurniawan")

	fmt.Println("Hasil Render Template:")
	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

214. Passing Dynamic Data ke Template (Struct, Map, Dynamic Field)

Mengirimkan data dinamis berupa Struct atau Map ke dalam template HTML.

Mengirim Data ke Template

type PageData struct {
    Title string
    Name  string
}

tmpl.Execute(w, PageData{Title: "Home", Name: "Eko"})

Di dalam HTML Template, field diakses menggunakan tanda titik: {{.Title}} dan {{.Name}}.

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
)

type UserProfile struct {
	Name string
	Role string
}

func main() {
	htmlTmpl := "<p>User: {{.Name}} | Role: {{.Role}}</p>"
	tmpl, _ := template.New("profile").Parse(htmlTmpl)

	var buf bytes.Buffer
	tmpl.Execute(&buf, UserProfile{Name: "Eko Khannedy", Role: "Software Engineer"})

	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

215. Template Actions (if, else, range, with)

Menambahkan logika pengondisian (if/else) dan perulangan (range) pada HTML Template.

Sintaks Template Actions

{{if .IsAdmin}}
    <p>Admin Dashboard</p>
{{else}}
    <p>User Dashboard</p>
{{end}}

{{range $index, $element := .Hobbies}}
    <li>{{$index}}: {{$element}}</li>
{{end}}

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
)

func main() {
	src := `Hobi:
{{range .Hobbies}}
 - {{.}}
{{end}}`
	tmpl, _ := template.New("hobbies").Parse(src)

	data := map[string]interface{}{
		"Hobbies": []string{"Coding", "Gaming", "Reading"},
	}

	var buf bytes.Buffer
	tmpl.Execute(&buf, data)

	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

216. Template Layout & Reusable Partials

Membuat struktur layout modular (Header, Footer, Content) dengan {{define}} dan {{template}}.

Template Layout

{{define "header"}}
    <header><h1>{{.Title}}</h1></header>
{{end}}

{{define "main"}}
    {{template "header" .}}
    <main><p>Konten Utama</p></main>
{{end}}

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
)

func main() {
	tmpl := template.New("layout")
	template.Must(tmpl.New("header").Parse("<header>Header Site</header>
"))
	template.Must(tmpl.New("body").Parse("{{template "header" .}}<main>Main Body</main>"))

	var buf bytes.Buffer
	tmpl.ExecuteTemplate(&buf, "body", nil)

	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

217. Custom Template Functions

Mendaftarkan fungsi buatan sendiri ke dalam HTML Template menggunakan template.FuncMap.

Custom FuncMap

funcMap := template.FuncMap{
    "upper": strings.ToUpper,
}
tmpl := template.New("test").Funcs(funcMap)

Penggunaan di HTML: {{upper .Name}}

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
	"strings"
)

func main() {
	funcMap := template.FuncMap{
		"upper": strings.ToUpper,
	}

	tmpl, _ := template.New("funcTest").Funcs(funcMap).Parse("Hello {{upper .}}")

	var buf bytes.Buffer
	tmpl.Execute(&buf, "kodeloka")

	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

218. Template Caching & Performance Optimization

Strategi mem-parse template sekali pada saat inisialisasi aplikasi untuk performa maksimal.

Template Caching

⚠️ Hindari Anti-Pattern:

Memanggil template.ParseFiles() di dalam fungsi HTTP Handler akan membaca ulang file dari disk pada setiap request (Sangat Lambat!).

✅ Solusi Caching:

Gunakan template.Must(template.ParseGlob("./templates/*.gohtml")) pada level global saat aplikasi pertama kali menyala.

Contoh program

package main

import (
	"fmt"
	"html/template"
)

// Template diparse sekali pada level paket/global
var templates = template.Must(template.New("app").Parse("<h1>Cached Template</h1>"))

func main() {
	fmt.Println("Template berhasil di-cache pada startup!", templates != nil)
}

Praktik dan kuis bab ini di kelas interaktif →

219. Keamanan Web: Mencegah XSS (Cross-Site Scripting)

Mekanisme proteksi auto-escaping HTML dan cara aman menangani konten HTML mentah.

Auto Escaping Security

Jika pengguna memasukkan input mengandung script jahat <script>alert('xss')</script>, html/template otomatis mengonversinya menjadi safe entities: &lt;script&gt;...

Jika ingin merender HTML asli tanpa escaping (hanya dari sumber terpercaya), gunakan tipe template.HTML.

Contoh program

package main

import (
	"bytes"
	"fmt"
	"html/template"
)

func main() {
	userInput := "<script>alert('hack')</script>"
	tmpl, _ := template.New("xss").Parse("Input: {{.}}
")

	var buf bytes.Buffer
	tmpl.Execute(&buf, userInput)

	fmt.Println("Hasil Render Safe Escaped:")
	fmt.Println(buf.String())
}

Praktik dan kuis bab ini di kelas interaktif →

220. HTTP Redirects (http.Redirect)

Mengalihkan halaman pengguna dari satu lokasi URL ke lokasi lain.

Penggunaan http.Redirect

func LoginHandler(w http.ResponseWriter, r *http.Request) {
    // Pengalihan ke halaman /dashboard dengan status 303 See Other
    http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
}

Contoh program

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	handler := func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/login", http.StatusSeeOther)
	}

	rec := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/old-path", nil)
	handler(rec, req)

	fmt.Println("Redirect Status Code:", rec.Code)
	fmt.Println("Redirect Location Header:", rec.Header().Get("Location"))
}

Praktik dan kuis bab ini di kelas interaktif →

221. Handling File Upload (r.FormFile)

Menerima dan memproses unggahan file dari form multipart/form-data.

File Upload Handling

file, header, err := r.FormFile("avatar")
if err != nil { return }
defer file.Close()

// Simpan file ke disk
targetFile, _ := os.Create("./uploads/" + header.Filename)
io.Copy(targetFile, file)

Contoh program

package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("=== FILE UPLOAD HANDLER ===")
	fmt.Println("1. HTML Form: enctype="multipart/form-data"")
	fmt.Println("2. Go Handler: file, header, err := r.FormFile("fieldname")")
	fmt.Println("3. Simpan dengan io.Copy(destFile, file)")
	_ = http.Request{}
}

Praktik dan kuis bab ini di kelas interaktif →

222. Download File Header (Content-Disposition)

Mengirim file ke pengguna dengan instruksi download otomatis di browser.

File Download

Untuk memaksa browser mengunduh file alih-alih mengabarkannya di layar, set header Content-Disposition:

w.Header().Set("Content-Disposition", "attachment; filename="laporan.pdf"")
http.ServeFile(w, r, "./files/laporan.pdf")

Contoh program

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	handler := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Disposition", "attachment; filename="document.txt"")
		fmt.Fprintln(w, "Isi dokumen rahasia")
	}

	rec := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/download", nil)
	handler(rec, req)

	fmt.Println("Header Content-Disposition:", rec.Header().Get("Content-Disposition"))
}

Praktik dan kuis bab ini di kelas interaktif →

223. Web Middleware Pattern

Membangun komponen Middleware (Logger, Auth, Recover) dengan membungkus http.Handler.

Pola Middleware di Go

type Middleware func(http.Handler) http.Handler

func LogMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Log Request:", r.Method, r.URL.Path)
        next.ServeHTTP(w, r) // Lanjut ke handler berikutnya
    })
}

Contoh program

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func SimpleLogMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("[LOG] Incoming Request:", r.URL.Path)
		next.ServeHTTP(w, r)
	})
}

func main() {
	mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Core Handler Executed")
	})

	wrapped := SimpleLogMiddleware(mainHandler)

	rec := httptest.NewRecorder()
	req := httptest.NewRequest("GET", "/dashboard", nil)
	wrapped.ServeHTTP(rec, req)
}

Praktik dan kuis bab ini di kelas interaktif →