Putting It All Together
Barchasini birlashtirish
Orkestr har bir cholg'uchi alohida mashq qilgandan keyin, hammasi birga bitta simfoniya chalganidek — biz ham shu paytgacha alohida-alohida qurgan qismlarni (Store, CodeGenerator, Shorten, Redirect) endi BITTA yaxlit oqim sifatida ishlatamiz: havola qisqartiriladi, VA o'sha qisqa kod orqali darhol yo'naltirish ham ishlaydi.
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
)
type URLRecord struct {
Code string
OriginalURL string
}
type Store struct{ records map[string]*URLRecord }
func NewStore() *Store { return &Store{records: make(map[string]*URLRecord)} }
func (s *Store) Save(r *URLRecord) { s.records[r.Code] = r }
func (s *Store) Get(code string) (*URLRecord, bool) { r, ok := s.records[code]; return r, ok }
type CodeGenerator struct{ counter int64 }
func (g *CodeGenerator) Next() string { g.counter++; return fmt.Sprintf("c%d", g.counter) }
type ShortenRequest struct {
URL string `json:"url"`
}
type ShortenResponse struct {
Code string `json:"code"`
}
func makeShortenHandler(gen *CodeGenerator, store *Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req ShortenRequest
json.NewDecoder(r.Body).Decode(&req)
code := gen.Next()
store.Save(&URLRecord{Code: code, OriginalURL: req.URL})
json.NewEncoder(w).Encode(ShortenResponse{Code: code})
}
}
func makeRedirectHandler(store *Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
code := strings.TrimPrefix(r.URL.Path, "/")
record, ok := store.Get(code)
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
http.Redirect(w, r, record.OriginalURL, http.StatusFound)
}
}
func main() {
store := NewStore()
gen := &CodeGenerator{}
mux := http.NewServeMux()
mux.HandleFunc("/shorten", makeShortenHandler(gen, store))
mux.HandleFunc("/", makeRedirectHandler(store))
// 1-qadam: havolani qisqartirish
shortenReq := httptest.NewRequest("POST", "/shorten", strings.NewReader(`{"url":"https://godasturchi.uz"}`))
shortenRec := httptest.NewRecorder()
mux.ServeHTTP(shortenRec, shortenReq)
var resp ShortenResponse
json.NewDecoder(shortenRec.Body).Decode(&resp)
// 2-qadam: o'sha kod orqali yo'naltirish
redirectReq := httptest.NewRequest("GET", "/"+resp.Code, nil)
redirectRec := httptest.NewRecorder()
mux.ServeHTTP(redirectRec, redirectReq)
fmt.Println(resp.Code, redirectRec.Code, redirectRec.Header().Get("Location"))
}http.NewServeMux() — "HTTP Routing" darsida ko'rgan router: /shorten yo'liga bitta handler, / (hamma boshqa yo'llar) uchun boshqa handler biriktiriladi. Bu — barcha alohida qurgan qismlarimizni BITTA ishlaydigan serverga aylantiruvchi "yelim".
Diqqat qiling: test ikkita ALOHIDA so'rovni simulyatsiya qiladi (avval /shorten, keyin natijada olingan kod bilan /{code}), lekin ikkalasi ham BIR XIL store va genga ishora qiladi — bu haqiqiy ikki foydalanuvchi so'rovi orasida serverning holati (state) qanday saqlanib qolishini ko'rsatadi.
>_ Exercise
Mavjud bo'lmagan kod bilan yo'naltirish so'ralganda 404 qaytishini tekshiring.
- •Yuqoridagi kabi mux'ni tuzing, lekin BEVOSITA "/notfound123" yo'liga GET so'rovi yuboring (avval shorten qilmasdan)
- •Natijadagi status kodni (redirectRec.Code) chop eting
Stuck? Reveal a hint to help you.
Key Takeaway
Key Takeaway:
http.NewServeMux orqali alohida qurilgan handlerlarni bitta serverga birlashtirish mumkin; ular umumiy Store orqali holatni baham ko'rib, yaxlit, ishlaydigan xizmat hosil qiladi.
NEXT UP
Project Recap & Next Steps
$ go run main.go
Kodingizni ishga tushiring