Idempotency Keys
Idempotentlik kalitlari
Bankomatdan pul yechayotganda, tarmoq bir lahzaga uzilib, ekranda "kutilmoqda" chiqib qoladi. Siz яна "tasdiqlash" tugmasini bosasiz. Yaxshi ishlab chiqilgan bankomat buni BILADI: u bitta AMALNI ikki marta bajarmaydi, chunki u har bir so'rovni NOYOB "amal raqami" bilan belgilaydi va shu raqamni ALLAQACHON bajarilgan bo'lsa, natijani QAYTA HISOBLAMASDAN eski natijani qaytaradi. Idempotentlik kaliti (Idempotency Key) — API'da aynan shu himoyani beradi: mijoz HAR BIR mantiqiy amal uchun noyob kalit yuboradi, server esa bitta kalitni IKKI MARTA bajarmaydi.
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"strings"
"sync"
)
type Book struct {
ID string `json:"id"`
Title string `json:"title"`
Author string `json:"author"`
Price float64 `json:"price"`
}
type BookStore struct {
mu sync.Mutex
books map[string]*Book
nextID int
}
func NewBookStore() *BookStore { return &BookStore{books: make(map[string]*Book)} }
func (s *BookStore) Create(title, author string, price float64) *Book {
s.mu.Lock()
defer s.mu.Unlock()
s.nextID++
id := strconv.Itoa(s.nextID)
book := &Book{ID: id, Title: title, Author: author, Price: price}
s.books[id] = book
return book
}
type IdempotencyStore struct {
mu sync.Mutex
results map[string]*Book
}
// GetOrCreate — key ALLAQACHON ko'rilgan bo'lsa, ESKI natijani qaytaradi (replayed=true);
// aks holda create() ni chaqirib, natijani key bilan ESLAB QOLADI
func (s *IdempotencyStore) GetOrCreate(key string, create func() *Book) (book *Book, replayed bool) {
s.mu.Lock()
defer s.mu.Unlock()
if existing, ok := s.results[key]; ok {
return existing, true
}
book = create()
s.results[key] = book
return book, false
}
func main() {
store := NewBookStore()
idem := &IdempotencyStore{results: make(map[string]*Book)}
mux := http.NewServeMux()
mux.HandleFunc("POST /books", func(w http.ResponseWriter, r *http.Request) {
key := r.Header.Get("Idempotency-Key")
var req struct {
Title string `json:"title"`
Author string `json:"author"`
Price float64 `json:"price"`
}
json.NewDecoder(r.Body).Decode(&req)
book, replayed := idem.GetOrCreate(key, func() *Book {
return store.Create(req.Title, req.Author, req.Price)
})
if replayed {
w.Header().Set("X-Idempotent-Replayed", "true")
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(book)
})
body := `{"title":"Go bilan tanishuv","author":"A. Karimov","price":45000}`
req1 := httptest.NewRequest("POST", "/books", strings.NewReader(body))
req1.Header.Set("Idempotency-Key", "key-123")
rec1 := httptest.NewRecorder()
mux.ServeHTTP(rec1, req1)
fmt.Println("1-urinish, replayed:", rec1.Header().Get("X-Idempotent-Replayed"))
req2 := httptest.NewRequest("POST", "/books", strings.NewReader(body))
req2.Header.Set("Idempotency-Key", "key-123")
rec2 := httptest.NewRecorder()
mux.ServeHTTP(rec2, req2)
fmt.Println("2-urinish (tarmoq qayta yuborgan), replayed:", rec2.Header().Get("X-Idempotent-Replayed"))
fmt.Println("bazadagi kitoblar soni:", len(store.books))
}IdempotencyStore.GetOrCreate — MARKAZIY g'oyani ifodalaydi: key (mijoz Idempotency-Key sarlavhasida yuborgan noyob satr) ALLAQACHON results xaritasida bo'lsa, create() funksiyasi UMUMAN chaqirilmaydi — ESKI natija QAYTARILADI. Aks holda, create() chaqiriladi VA natija key bilan SAQLANADI, keyingi safar QAYTA ishlatish uchun.
E'tibor bering: ikkinchi so'rov (xuddi shu "key-123" bilan) store.Create ni UMUMAN chaqirmadi — natijada store.booksda FAQAT bitta kitob bor, garchi POST /books IKKI marta chaqirilgan bo'lsa ham. Bu — HAQIQIY hayotda mijoz "internet uzildi, yana bosayapman" deganda YUZ beradigan vaziyatni AYNAN takrorlaydi: server bitta AMALNI IKKI MARTA bajarmaydi.
>_ Exercise
Idempotentlikning "faqat BIR KALIT uchun" ishlashini isbotlang.
- •yordamchi send(key string) funksiyasini yozing: berilgan Idempotency-Key bilan bitta POST /books so'rovi yuborsin
- •send("key-123") ni IKKI marta chaqiring (xuddi shu kalit — tarmoq qayta yuborgani)
- •send("key-456") ni BIR marta chaqiring (BOSHQA kalit — bu YANGI, mustaqil amal)
- •oxirida store.books xaritasidagi kitoblar SONINI chop eting
Stuck? Reveal a hint to help you.
Key Takeaway
Key Takeaway:
Idempotentlik kaliti — mijoz tarmoq xatosi tufayli BIR XIL so'rovni QAYTA yuborganda, serverning uni IKKI MARTA bajarib yubormasligini kafolatlaydi; kalit ESLAB QOLINGAN natijani qaytarish orqali, amal FAQAT bir marta haqiqatan sodir bo'ladi.
NEXT UP
API Versioning Strategies
$ go run main.go
Kodingizni ishga tushiring