Barbarian is an simple HTTP client that helps your application with circuit breaker
All HTTP methods are exposed as a fluent interface.
go get -u github.com/dyaksa/barbarian
This package can be used by adding the following import statement to your .go
files.
import "github.com/dyaksa/barbarian/client"
The below example will print the contents:
// Create a new HTTP client with a default timeout
client := httpclient.NewClient(&httpclient.Config{
BaseUrl: "http://localhost:3001", // baseurl
HTTPTimeout: 30 * time.Second, // http timeout
})
// Use the clients GET method to create and execute the request
res, err := client.Get(context.Background(), "/test")
if err != nil {
panic(err)
}
// Barbarian returns the standard *http.Response object
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
You can also use the *http.Request
object with the http.Do
interface :
client := httpclient.NewClient(&httpclient.Config{
HTTPTimeout: 30 * time.Second, // http timeout
})
// Create an http.Request instance
req, _ := http.NewRequest(http.MethodGet, "http://google.com", nil)
// Call the `Do` method, which has a similar interface to the `http.Do` method
res, err := client.Do(req)
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
You can configure CircuitBreaker
by the struct Settings
:
client := httpclient.NewClient(&httpclient.Config{
Name: "test",
ConsiderServerErrorAsFailure: true,
ServerErrorThreshold: 500,
Timeout: 30 * time.Second,
OnStateChange: func(name string, to, from httpclient.State) {
fmt.Printf("State change from %s to %s\n", from, to)
},
ReadyToTrip: func(cunts httpclient.Counts) bool {
return cunts.TotalFailures >= 2
},
})
req, _ := http.NewRequest(http.MethodGet, "http://google.com", nil)
if err != nil {
panic(err)
}
// Call the `Do` method, which has a similar interface to the `http.Do` method
res, err := client.Do(req)
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
-
Name
is the name of theCircuitBreaker
. -
ConsiderServerErrorAsFailure
Determines whether server errors should trigger the circuit breaker. -
ServerErrorThreshold
Specifies the HTTP status code threshold at which the circuit breaker should open. -
MaxRequests
is the maximum number of requests allowed to pass through when theCircuitBreaker
is half-open. IfMaxRequests
is 0,CircuitBreaker
allows only 1 request. -
Interval
is the cyclic period of the closed state forCircuitBreaker
to clear the internalCounts
, described later in this section. IfInterval
is 0,CircuitBreaker
doesn't clear the internalCounts
during the closed state. -
Timeout
is the period of the open state, after which the state ofCircuitBreaker
becomes half-open. IfTimeout
is 0, the timeout value ofCircuitBreaker
is set to 60 seconds. -
ReadyToTrip
is called with a copy ofCounts
whenever a request fails in the closed state. IfReadyToTrip
returns true,CircuitBreaker
will be placed into the open state. IfReadyToTrip
isnil
, defaultReadyToTrip
is used. DefaultReadyToTrip
returns true when the number of consecutive failures is more than 5. -
OnStateChange
is called whenever the state ofCircuitBreaker
changes. -
IsSuccessful
is called with the error returned from a request. IfIsSuccessful
returns true, the error is counted as a success. Otherwise the error is counted as a failure. IfIsSuccessful
is nil, defaultIsSuccessful
is used, which returns false for all non-nil errors.
You can call options GET
by the method Options
:
client := httpclient.NewClient(&httpclient.Config{
Name: "http client",
BaseUrl: "http://localhost:3001",
})
headers := map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
}
res, err := client.Get(context.Background(), "/test",
httpclient.WithHeaders(headers),
httpclient.BodyJSON(map[string]interface{}{"name": "John Doe"}),
)
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
To add a plugin to an existing client, use the AddPlugin
method of the client.
An example, with the logger plugin:
// import "github.com/dyaksa/barbarian/plugins"
client := httpclient.NewClient(&httpclient.Config{
Name: "http client",
BaseUrl: "http://localhost:3001",
HTTPTimout: 30 * time.Second
})
logger := plugins.NewLogger(nil, nil)
client.AddPlugin(logger)
res, err := client.Get(context.Background(), "/test", nil)
if err != nil {
panic(err)
}
// This will log:
//23/Aug/2024 12:48:04 GET http://localhost:3001 200 [412ms]
// to STDOUT
A plugin is an interface whose methods get called during key events in a requests lifecycle:
OnRequestStart
is called just before the request is madeOnRequestEnd
is called once the request has successfully executedOnError
is called is the request failedNextInterval
is called the request retry mechanism
Each method is called with the request object as an argument, with OnRequestEnd
, and OnError
additionally being called with the response and error instances respectively.
client := httpclient.NewClient(&httpclient.Config{
Name: "test",
BaseUrl: "https://webhook.site",
ConsiderServerErrorAsFailure: true,
ServerErrorThreshold: 500,
RetryCount: 5,
ReadyToTrip: func(cunts httpclient.Counts) bool {
return cunts.TotalFailures > 2
},
Timeout: 30 * time.Second,
})
// Create a new retry mechanism with the backoff
retrier := plugins.NewRetrier(plugins.NewConstantBackoff(1*time.Second, 1))
// Create a new client, sets the retry mechanism, and the number of times you would like to retry
client.AddPlugin(retrier)
Copyright 2024
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.