ماڈیول اسباق (5/5)
منی پروجیکٹ: ایک HTTP سرور
net/http stdlib پیکیج پروڈکشن کے لیے تیار HTTP سرور بنانے کے لیے کافی ہے: روٹنگ، ہینڈلرز، مڈل ویئر، شاندار شٹ ڈاؤن۔ کسی فریم ورک کی ضرورت نہیں ہے۔ عام REST APIs کے لیے یہ بنیاد ہے۔
ہیلو دنیا
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello %s", r.URL.Path[1:])
})
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}http.ListenAndServe بلاک کرتا ہے اور صرف غلطی پر واپس آتا ہے۔ nil بطور دوسری دلیل = "استعمال کریں DefaultServeMux"۔
ہینڈلر کے دستخط
تمام ہینڈلرز ایک ہی دستخط کا اشتراک کرتے ہیں:
func(w http.ResponseWriter, r *http.Request)w http.ResponseWriter— آؤٹ پٹ: ہیڈر، اسٹیٹس کوڈ، باڈی۔r *http.Request— ان پٹ: طریقہ، URL، ہیڈر، باڈی، سیاق و سباق۔
عام پیٹرن:
func ping(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // optional, defaults to 200
fmt.Fprintln(w, `{"ok":true}`)
}ServeMux کے ساتھ روٹنگ
*http.ServeMux بنیادی روٹر ہے۔ چونکہ Go 1.22 یہ طریقہ اور راستے کے پیرامیٹرز کے ساتھ پیٹرن کو سپورٹ کرتا ہے:
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintln(w, "user", id)
})
mux.HandleFunc("POST /users", createUser)
http.ListenAndServe(":8080", mux)مزید نفیس راؤٹرز (گروپس، انٹیگریٹڈ مڈل ویئر، ریجیکس) کے لیے chi، gorilla/mux، gin، echo ہے۔ stdlib 90% مقدمات کا احاطہ کرتا ہے۔
مڈل ویئر بطور ڈیکوریٹر
ایک مڈل ویئر ایک فنکشن ہے func(http.Handler) http.Handler:
func logMW(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
})
}
http.ListenAndServe(":8080", logMW(mux))انہیں زنجیر بنانے کے لیے: logMW(authMW(rateLimitMW(mux)))۔ ہر مڈل ویئر اگلے کو سجاتا ہے۔
ٹھیک کنٹرول کے لیے http.Server
http.ListenAndServe(addr, h) ایک شارٹ کٹ ہے۔ ٹائم آؤٹ، TLS، اور خوبصورت شٹ ڈاؤن کے لیے آپ کو فوری طور پر http.Server:
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 2 * time.Minute,
}
log.Fatal(srv.ListenAndServe())سیاق و سباق کے ساتھ خوبصورت بند
جب عمل کو SIGINT/SIGTERM موصول ہوتا ہے، تو آپ بند کرنے سے پہلے پرواز میں درخواستیں ختم کرنا چاہتے ہیں:
ctx, stop := signal.NotifyContext(context.Background(),
os.Interrupt, syscall.SIGTERM)
defer stop()
srv := &http.Server{Addr: ":8080", Handler: mux}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
<-ctx.Done() // wait for the signal
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
log.Println("shutdown:", err)
}srv.Shutdown نئے کنکشنز کو قبول کرنا بند کر دیتا ہے اور ایکٹیو کنکشن کے مکمل ہونے کا انتظار کرتا ہے (گزرنے والی آخری تاریخ تک)۔
JSON باڈی پڑھنا
type CreateUserReq struct {
Name string `json:"name"`
}
func createUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// ... use req.Name
w.WriteHeader(http.StatusCreated)
}r.Body ایک io.ReadCloser ہے: سرور اسے خود بخود بند کر دیتا ہے، لیکن json.NewDecoder پہلے JSON آبجیکٹ کو نہیں پڑھتا (ان پٹ کی توثیق کے لیے مفید)۔
مشقیں
رجسٹرا l'handler hello sulla route '/' usando http.HandleFunc.
3 کوششوں کے بعد حل دستیاب ہے۔
Avvia il server su :8080 con http.ListenAndServe e stampa l'errore se non è nil.
3 کوششوں کے بعد حل دستیاب ہے۔
Qual è la firma idiomatica di un handler HTTP گو میں؟
func H(???) { ... }