the go-enrichable-client
package is wrapper over the standard net/http
client library
allowing to enrich it functionality by using middleware extensions.
go get github.com/shuvava/go-enrichable-client
Example of pure http.client usage
package main
import "github.com/shuvava/go-enrichable-client/client"
func main() {
var responseObject ResponseObject
// make GET request and deserialize response body
// using default http client with with idle connections
// and keepalives disabled.
err := client.Get(url, &responseObject)
...
}
package main
import (
"net/http"
"github.com/shuvava/go-enrichable-client/client"
"github.com/shuvava/go-enrichable-client/middleware"
)
func main() {
// create enriched client
c := client.DefaultClient()
// add custom middleware
c.Use(
func(c *http.Client, next client.Responder) client.Responder {
return func(request *http.Request) (*http.Response, error) {
// logic before doing request
res, err:= next(request)
// logic after doing request
return res, err
}
})
...
}
Name | Description |
---|---|
Retry | add retry functionality |
OAuth | add bearer authorization token to all request |
CircuitBreaker | add Circuit Breaker to all request |
UserAgent | add User-Agent header to all requests |
This middleware adds retry functionality with automatic retries and exponential backoff policy. Currently, package supports only json content type
package main
import (
"github.com/shuvava/go-enrichable-client/client"
"github.com/shuvava/go-enrichable-client/middleware"
)
func main() {
...
// create enriched client
c := client.DefaultClient()
// add retry middleware
c.Use(middleware.Retry())
// receive reference to http.Client
err := c.Get(url, &responseObject)
...
}
With machine-to-machine (M2M) applications, such as CLIs, daemons, or services running on your back-end, the system authenticates and authorizes the app rather than a user. For this scenario, typical authentication schemes like username + password or social logins don't make sense. Instead, M2M apps use the Client Credentials Flow (defined in OAuth 2.0 RFC 6749, section 4.4), in which they pass along their Client ID and Client Secret to authenticate themselves and get a token.
package main
import (
"fmt"
"github.com/shuvava/go-enrichable-client/client"
"github.com/shuvava/go-enrichable-client/middleware"
)
func main() {
...
// create enriched client
c := client.DefaultClient()
// add oauth middleware
tenant := "00000000-0000-0000-0000-000000000000"
uri := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenant)
oauthConifg := middleware.OAuthConfig{
AuthServerURL: uri,
ClientID: "00000000-0000-0000-0000-000000000000",
ClientSecret: "some secret",
Scope: "api://00000000-0000-0000-0000-000000000000/.default",
}
c.Use(middleware.OAuth(oauthConifg))
...
}
The Circuit Breaker pattern can prevent an application repeatedly trying to execute an operation that is likely to fail, allowing it to continue without waiting for the fault to be rectified or wasting CPU cycles while it determines that the fault is long lasting. The Circuit Breaker pattern also enables an application to detect whether the fault has been resolved. If the problem appears to have been rectified, the application can attempt to invoke the operation.
ou can configure CircuitBreaker
by the struct Settings
:
type CircuitBreakerSettings struct {
MaxRequests uint32
Interval time.Duration
Timeout time.Duration
ReadyToTrip func(counts Counts) bool
OnStateChange func(name string, from State, to State)
}
MaxRequests
is the maximum number of requests allowed to pass through when theCircuitBreakerService
is half-open. IfMaxRequests
is 0,CircuitBreakerService
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,CircuitBreakerService
doesn't clear the internalCounts
during the closed state.Timeout
is the period of the open state, after which the state ofCircuitBreakerService
becomes half-open. IfTimeout
is 0, the timeout value ofCircuitBreakerService
is set to 60 seconds.ReadyToTrip
is called with a copy ofCounts
whenever a request fails in the closed state. IfReadyToTrip
returns true,CircuitBreakerService
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 ofCircuitBreakerService
changes. The structCircuitBreakerCounts
holds the numbers of requests and their successes/failures:
type CircuitBreakerCounts struct {
Requests uint32
TotalSuccesses uint32
TotalFailures uint32
ConsecutiveSuccesses uint32
ConsecutiveFailures uint32
}
CircuitBreakerService
clears the internal CircuitBreakerCounts
either
on the change of the state or at the closed-state intervals.
CircuitBreakerCounts
ignores the results of the requests sent before clearing.
package main
import (
"github.com/shuvava/go-enrichable-client/client"
"github.com/shuvava/go-enrichable-client/middleware"
)
func main() {
...
// create enriched http client
c := client.DefaultClient()
// add circuit breaker middleware
c.Use(middleware.CircuitBreaker(middleware.CircuitBreakerSettings{}))
...
}
UserAgent is a middleware that add the user agent string into request http.Header.
package main
import (
"github.com/shuvava/go-enrichable-client/client"
"github.com/shuvava/go-enrichable-client/middleware"
)
func main() {
...
// create enriched http client
c := client.DefaultClient()
// add user-agent middleware
c.Use(middleware.UserAgent(middleware.UserAgentConfig{App: "app-name", Version: "1.0.0"}))
...
}