README
¶
Roku
Overview
The Roku REST client provides a straightforward and simple interface for interacting with REST APIs. With Roku you can:
- Easily marshal and unmarshal requests and responses without the need for boilerplate or repetitive code.
- Utilize the built-in exponential backoff algorithm.
- Enhance your request functions by wrapping them with RxGo 2 Observable streams, enabling the creation of custom pipelines, including parallel requests.
Table of Contents
Usage.
-
Before starting to make requests, we need to create a *http.Client in Golang. For this, we can use Roku's constructor method:
import ( ... "github.com/v8tix/roku" "net/http" ... ) func NewHTTPClient( timeout time.Duration, redirectPolicy func(req *http.Request, via []*http.Request) error, transport http.RoundTripper, ) *http.Client { ... }
-
Where:
timeout: Its purpose is to control how long the client waits to receive a response from the server before considering the request as failed due to a timeout.
redirectPolicy: Its purpose is to allow you to control how the HTTP client handles 3xx redirection responses.
transport: Its purpose is to allow you to have more granular control over how HTTP requests are made and how network connections are managed. -
Example:
httpClient := roku.NewHTTPClient( 5*time.Second, policy.OneRedirect, transport.IdleConnectionTimeout(15*time.Second), )
The OneRedirect and IdleConnectionTimeout functions are examples of how the Golang REST client can be configured and are part of Roku. -
*Once our client is configured, we can start configuring the functions provided by Roku: Fetch and FetchRx. The difference between them is that Fetch does not provide a backoff mechanism and does not return the response as an observable. For production environments, we recommend using Rx.
- FetchRx signature:
func FetchRx[T ReqI, U ResI](
ctx context.Context,
client *http.Client,
method HTTPMethod,
endpoint string,
request *T,
headers map[string]string,
deadline time.Duration,
backoffInterval time.Duration,
backoffRetries uint64,
statusCodeValidator ...func(res *http.Response) bool,
) rxgo.Observable {
...
}
- FetchRx example:
ch := roku.FetchRx[CreateUserV1Req, GetUserEnvV1Res](
context.Background(),
httpClient,
roku.Put,
url,
createUserV1Req,
nil,
time.Second,
150 * time.Millisecond,
3,
).Observe()
res, err := roku.To[roku.Envelope[GetUserEnvV1Res]](<-ch)
switch err {
case nil:
if res.Body != nil {
...
return res.Body.User
}
default:
var errHTTP roku.ErrInvalidHTTPStatus
if errors.As(err, &errHTTP) {
errDesc := roku.GetErrorDesc(errHTTP)
return fmt.Errorf("http error: %v", errDesc)
}
}
- Notes about the example:
- Due to generics in Golang, CreateUserV1Req and GetUserEnvV1Res must implement the roku.ReqI and roku.ResI interfaces, respectively.
type CreateUserV1Req struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
}
func (CreateUserV1Req) Req() {}
type GetUserEnvV1Res struct {
User GetUserV1Res `json:"user,omitempty"`
}
func (GetUserEnvV1Res) Res() {}
- In cases where the request does not have a request body, you should use the type roku.NoReq and pass nil as a parameter to FetchRx.
- In cases where the request does not return a response, you should use the type roku.NoRes for FetchRx.
ch:= roku.FetchRx[roku.NoReq, roku.NoRes](
ctx,
httpClient,
roku.Delete,
url,
nil,
nil,
roku.DeadLine,
roku.RetryInterval,
3,
).Observe()
_, err := roku.To[roku.Envelope[roku.NoRes]](<-ch)
switch err {
case nil:
return nil
default:
var errHTTP roku.ErrInvalidHTTPStatus
if errors.As(err, &errHTTP) {
errDesc := roku.GetErrorDesc(errHTTP)
return fmt.Errorf("http error: %v", errDesc)
}
}
- deadline: It enables FetchRx to block requests to the service, preventing both overloading and cascading failures.
- backoffInterval: It represents a waiting period in which FetchRx delays before attempting to retry a failed request.
- backoffRetries: It represents the maximum number of retry attempts that FetchRx will make for a request.
Contributing.
- Fork the repository
- Clone the forked repository
- Create a new branch for your feature or fix
- Make your changes
- Submit a pull request
License.
This project is licensed under the MIT License. You can refer to the LICENSE file for more information.
Documentation
¶
Index ¶
- Constants
- Variables
- func FetchRx[T ReqI, U ResI](ctx context.Context, client *http.Client, method HTTPMethod, endpoint string, ...) rxgo.Observable
- func NewHTTPClient(timeout time.Duration, ...) *http.Client
- func ReadJSON(body io.Reader, dst any) error
- func To[T any](item rxgo.Item) (*T, error)
- type Envelope
- type ErrDesc
- type ErrInvalidHTTPStatus
- type HTTPMethod
- type NoReq
- type NoRes
- type ReqI
- type ReqURLI
- type ResI
Constants ¶
const ( Get = HTTPMethod("GET") Post = HTTPMethod("POST") Put = HTTPMethod("PUT") Patch = HTTPMethod("PATCH") Delete = HTTPMethod("DELETE") ConTimeOut = 15 * time.Second )
Variables ¶
var ( ErrTimeOut = rokuErr("timeout occurred") ErrMarshallValue = rokuErr("failed to marshal the value to JSON") ErrBadRequest = rokuErr("bad request") ErrNonPointerOrWrongCasting = rokuErr("value is not a pointer or casting type is incorrect") ErrEmptyItem = rokuErr("item has no value and no error") ErrNilValue = rokuErr("nil value provided") ErrNilRequest = rokuErr("nil request provided") ErrBadlyJSON = rokuErr("badly-formed JSON in the body") ErrBadJSONType = rokuErr("incorrect JSON type in the body") ErrEmptyBody = rokuErr("body must not be empty") ErrBodyUnknownKey = rokuErr("unknown key in the body") ErrBodySizeLimit = rokuErr("body size limit exceeded") ErrBodyValue = rokuErr("body must contain a single JSON value") )
Functions ¶
func NewHTTPClient ¶
Types ¶
type ErrDesc ¶
type ErrDesc struct { StatusCode int `json:"status_code,omitempty"` Status string `json:"status,omitempty"` ErrMessage string `json:"error_message,omitempty"` }
func GetErrorDesc ¶
func GetErrorDesc(errHTTP ErrInvalidHTTPStatus) ErrDesc
type ErrInvalidHTTPStatus ¶
func (ErrInvalidHTTPStatus) UnmarshalError ¶
func (e ErrInvalidHTTPStatus) UnmarshalError() (ErrDesc, error)
type HTTPMethod ¶
type HTTPMethod string