Lompat ke konten
dokumentasi.id
Commit ecba1e8
v2
Star2,8 rb

Kamu membaca versi lama. Halaman ini hanya bisa dibaca.

4

Klien HTTP Dasar

httpclient.Client adalah implementasi default dari interface heimdall.Client untuk melakukan panggilan HTTP. Struct ini membungkus sebuah heimdall.Doer, menyimpan daftar plugin, dan menampung seluruh state retry. Baris var _ heimdall.Client = (*Client)(nil) memastikan struct ini selalu memenuhi interface tersebut. httpclient/client.go:16-25 httpclient/client.go:32

Interface heimdall.Client hanya berisi lima method pembungkus HTTP, satu method Do, dan satu method AddPlugin, sehingga tipe lain yang memenuhi kontrak yang sama bisa dipakai bergantian dengan httpclient.Client. client.go:15-23 Kontrak Doer yang lebih kecil hanya menuntut satu method Do(*http.Request) (*http.Response, error). client.go:10-12

Komposisi struct

Diagram berikut menunjukkan bagaimana NewClient mengisi field Client: sebagian field punya nilai default, sebagian lain hanya terisi lewat Option.

graph TD
  NewClient["httpclient.NewClient"] --> Client["Client"]
  NewClient --> NetClient["*http.Client (Timeout = defaultHTTPTimeout)"]
  NewClient --> Opt["httpclient.Option"]
  Opt --> Timeout["timeout *time.Duration"]
  Opt --> Retrier["retrier heimdall.Retriable"]
  Opt --> RetryCount["retryCount int"]
  Opt --> Codes["retryableCodes []int"]
  Opt --> Budget["retryErrorBudget *internal.ErrorBudget"]
  Client --> Doer["client heimdall.Doer"]
  Client --> Plugins["plugins []heimdall.Plugin"]
  Client --> Timeout
  Client --> Retrier
  Client --> RetryCount
  Client --> Codes
  Client --> Budget
  NetClient --> Doer
  style NetClient fill:#336791,color:#fff
  style Client fill:#f59e0b,color:#000
  style Opt fill:#f59e0b,color:#000
  style Doer fill:#8b5cf6,color:#fff
  style Plugins fill:#8b5cf6,color:#fff
  style Timeout fill:#f59e0b,color:#000
  style Retrier fill:#f59e0b,color:#000
  style RetryCount fill:#f59e0b,color:#000
  style Codes fill:#f59e0b,color:#000
  style Budget fill:#f59e0b,color:#000
  %% fig: Komposisi struct httpclient.Client
  %% desc: NewClient mengisi field Client lewat Option, sementara tanpa opsi klien memakai *http.Client dengan timeout default dan NoRetrier.
Fig. 1: Komposisi struct httpclient.ClientNewClient mengisi field Client lewat Option, sementara tanpa opsi klien memakai *http.Client dengan timeout default dan NoRetrier.

client bertipe heimdall.Doer sehingga implementasi net/http bisa diganti sepenuhnya; plugins menampung semua heimdall.Plugin; retryableCodes menyimpan status code tambahan yang boleh diulang; dan retryErrorBudget menunjuk ke internal.ErrorBudget yang membatasi retry. httpclient/client.go:16-25

Field dan tipe

FieldTipePeran
clientheimdall.DoerEksekutor HTTP yang sebenarnya dipanggil di dalam Do
plugins[]heimdall.PluginDaftar plugin yang menerima callback request
timeout*time.DurationNilai timeout yang diterapkan ke *http.Client
retrierheimdall.RetriableSumber interval jeda antar percobaan
retryCountintJumlah maksimum percobaan ulang
retryableCodes[]intStatus code tambahan yang dianggap layak diulang
retryErrorBudget*internal.ErrorBudgetPembatas retry berbasis error budget

Method pembungkus HTTP

Lima method pembungkus membuat *http.Request sendiri, menyalin headers ke request.Header, lalu menyerahkan eksekusinya ke Do. Get dan Delete mengirim body nil, sedangkan Post, Put, dan Patch menerima body io.Reader. httpclient/client.go:57-67 httpclient/client.go:69-106 httpclient/client.go:109-119

MethodSignatureBody request
GetGet(url string, headers http.Header)nil
PostPost(url string, body io.Reader, headers http.Header)io.Reader
PutPut(url string, body io.Reader, headers http.Header)io.Reader
PatchPatch(url string, body io.Reader, headers http.Header)io.Reader
DeleteDelete(url string, headers http.Header)nil
DoDo(req *http.Request)ditentukan pemanggil

Kegagalan membuat request tidak dikirim ke jaringan. Setiap method mengembalikan *http.Response bernilai nil beserta error yang dibungkus dengan pesan seperti "GET - request creation failed: %w". httpclient/client.go:57-67

graph LR
  Get["Get / Delete"] --> NewReq["http.NewRequest dengan body nil"]
  Body["Post / Put / Patch"] --> NewReq2["http.NewRequest dengan body io.Reader"]
  NewReq --> Header["request.Header = headers"]
  NewReq2 --> Header
  Header --> Do["Client.Do(request)"]
  Do --> Doer["heimdall.Doer.Do"]
  Do --> Plugins["reportRequestStart / reportRequestEnd / reportError"]
  style Get fill:#2d7d46,color:#fff
  style Body fill:#2d7d46,color:#fff
  style NewReq fill:#8b5cf6,color:#fff
  style NewReq2 fill:#8b5cf6,color:#fff
  style Header fill:#8b5cf6,color:#fff
  style Do fill:#f59e0b,color:#000
  style Doer fill:#336791,color:#fff
  style Plugins fill:#8b5cf6,color:#fff
  %% fig: Delegasi method pembungkus ke Client.Do
  %% desc: Setiap method pembungkus menyiapkan *http.Request lalu menyerahkan eksekusi ke Do, yang memanggil Doer dan melaporkan event ke plugin.
Fig. 2: Delegasi method pembungkus ke Client.DoSetiap method pembungkus menyiapkan *http.Request lalu menyerahkan eksekusi ke Do, yang memanggil Doer dan melaporkan event ke plugin.

Do juga menutup body request asli setelah pemanggilan selesai, sehingga pemanggil tidak perlu menutup body request yang dioper ke sana. httpclient/client.go:121-128 Karena Do menerima *http.Request yang sudah jadi, header dan body sepenuhnya menjadi tanggung jawab pemanggil pada jalur ini. Rangkaian percobaan ulang di dalam Do beserta urutan callback plugin dibahas di Siklus Request dan Retry.

Nilai default dan timeout

Dua konstanta menentukan perilaku awal klien: defaultRetryCount bernilai 0 dan defaultHTTPTimeout bernilai 30 * time.Second. httpclient/client.go:27-30

NewClient membuat http.Client dengan Timeout: defaultHTTPTimeout, memakai defaultRetryCount, dan memasang heimdall.NewNoRetrier() sebagai retrier. Setelah semua Option dijalankan, updateHTTPTimeout dipanggil sekali lagi. httpclient/client.go:34-49

FieldNilai defaultSumber
retryCountdefaultRetryCount = 0httpclient/client.go:27-30
http.Client.TimeoutdefaultHTTPTimeout = 30 * time.Secondhttpclient/client.go:27-30
retrierheimdall.NewNoRetrier()httpclient/client.go:34-49

WithHTTPTimeout menyimpan durasi ke field timeout lalu langsung memanggil updateHTTPTimeout, bukan menimpa http.Client secara langsung. httpclient/options.go:14-21

updateHTTPTimeout hanya menulis ke http.Client bila field client benar-benar bertipe *http.Client; jika tidak, nilai timeout diabaikan tanpa error. httpclient/client.go:222-230

⚠️ Memasang Doer kustom lewat WithHTTPClient membuat WithHTTPTimeout tidak berpengaruh, karena Doer tersebut bukan *http.Client. Timeout pada kasus itu harus ditangani sendiri oleh implementasi Doer. httpclient/client.go:222-230

Opsi lain yang mengisi field di atas, termasuk WithRetryCount dan WithRetryableStatusCodes, dijelaskan di Option pada httpclient.

Menambahkan plugin

AddPlugin hanya menambahkan plugin ke slice plugins; tidak ada validasi dan tidak ada penggantian plugin yang sudah ada. httpclient/client.go:51-54 Setiap plugin wajib memenuhi interface heimdall.Plugin dengan tiga method: OnRequestStart, OnRequestEnd, dan OnError. plugin.go:9-13

Ketiga method itu dipanggil lewat tiga helper terpisah yang mengiterasi seluruh isi plugins: reportRequestStart sebelum request dieksekusi, reportRequestEnd setelah response diperoleh, dan reportError saat terjadi error. httpclient/client.go:204-220

graph TD
  AddPlugin["Client.AddPlugin"] --> Plugins["plugins []heimdall.Plugin"]
  Plugins --> Start["reportRequestStart"]
  Plugins --> End["reportRequestEnd"]
  Plugins --> Err["reportError"]
  Start --> OnStart["Plugin.OnRequestStart"]
  End --> OnEnd["Plugin.OnRequestEnd"]
  Err --> OnError["Plugin.OnError"]
  style AddPlugin fill:#f59e0b,color:#000
  style Plugins fill:#8b5cf6,color:#fff
  style OnStart fill:#2d7d46,color:#fff
  style OnEnd fill:#2d7d46,color:#fff
  style OnError fill:#dc2626,color:#fff
  style Start fill:#8b5cf6,color:#fff
  style End fill:#8b5cf6,color:#fff
  style Err fill:#dc2626,color:#fff
  %% fig: Jalur plugin pada httpclient.Client
  %% desc: AddPlugin menambah elemen ke slice plugins, lalu helper reportRequestStart, reportRequestEnd, dan reportError meneruskan event ke setiap plugin.
Fig. 3: Jalur plugin pada httpclient.ClientAddPlugin menambah elemen ke slice plugins, lalu helper reportRequestStart, reportRequestEnd, dan reportError meneruskan event ke setiap plugin.

Contoh plugin dan logger yang siap dipakai ada di Plugin dan Request Logger.

Contoh pemakaian

Pemakaian paling ringkas membuat klien dengan timeout, jumlah retry, dan retrier, lalu memanggil Get dengan headers yang sudah disiapkan. Response harus dibaca dari response.Body dan ditutup oleh pemanggil. examples/client.go:18-43

timeout := 100 * time.Millisecond
httpClient := httpclient.NewClient(
	httpclient.WithHTTPTimeout(timeout),
	httpclient.WithRetryCount(2),
)
response, err := httpClient.Get(baseURL, headers)

Pola yang sama dipakai di README: klien dibuat dengan httpclient.NewClient(httpclient.WithHTTPTimeout(timeout)), Get dipanggil dengan nil header, dan body dibaca memakai io.ReadAll. README.md:52-65