When building an SDK, you can wrap *req.Client in a custom struct. Use SetCommonErrorResult to define a standard error structure and OnAfterResponse to intercept responses. In the interceptor, you can convert API-level error responses into standard Go errors by checking resp.ErrorResult() and assigning it to resp.Err.
import (
"context"
"fmt"
"github.com/imroc/req/v3"
)
type ErrorMessage struct {
Message string `json:"message"`
}
func (msg *ErrorMessage) Error() string {
return fmt.Sprintf("API Error: %s", msg.Message)
}
type GithubClient struct {
*req.Client
}
func NewGithubClient() *GithubClient {
return &GithubClient{
Client: req.C().
SetBaseURL("https://api.github.com").
SetCommonErrorResult(&ErrorMessage{}).
EnableDumpEachRequest().
OnAfterResponse(func(client *req.Client, resp *req.Response) error {
if resp.Err != nil {
return nil
}
if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok {
resp.Err = errMsg
return nil
}
if !resp.IsSuccessState() {
resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump())
return nil
}
return nil
}),
}
}
type UserProfile struct {
Name string `json:"name"`
Blog string `json:"blog"`
}
func (c *GithubClient) GetUserProfile_Style1(ctx context.Context, username string) (user *UserProfile, err error) {
_, err = c.R().
SetContext(ctx).
SetPathParam("username", username).
SetSuccessResult(&user).
Get("/users/{username}")
return
}
func (c *GithubClient) GetUserProfile_Style2(ctx context.Context, username string) (user *UserProfile, err error) {
err = c.Get("/users/{username}").
SetPathParam("username", username).
Do(ctx).
Into(&user)
return
}