GoDasturchi
Putting It All Together

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.

example.go
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.

Hints (0/3)

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

OUTPUT

$ go run main.go
Kodingizni ishga tushiring

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.

example.go
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.

Hints (0/3)

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