Requester (HTTP client)
core.IRequester — outbound HTTP, backed by go-resty. ctx.Requester() reuses a shared client (connection pool kept alive).
The API is deliberately thin: you build requests with the full go-resty API via R(), and run them with Send, which is the only thing the framework wraps — it binds the request context and converts every failure (transport error or non-2xx status) into a core.IError.
Basic usage
go
r := ctx.Requester()
var out UserDTO
resp, err := r.Send(r.R().SetResult(&out), http.MethodGet, "https://api/users/1")
if err != nil {
return err // IError — return it straight from a handler
}
_ = resp // *resty.Response (status, headers, raw body, trace info)err is a core.IError:
- transport failure → code
NETWORK_ERROR, status 500 - non-2xx status → the response status, reusing the remote
code/messagewhen the JSON body provides them - success →
nil
Full go-resty when building
R() returns a *resty.Request already bound to the context, so anything resty offers is available; Send just executes and wraps the error:
go
// headers, query, auth, typed result
var out UserDTO
resp, err := r.Send(
r.R().
SetHeader("X-Token", token).
SetQueryParam("q", "search").
SetAuthToken(bearer).
SetResult(&out),
http.MethodGet, url,
)
// JSON body
resp, err = r.Send(r.R().SetBody(payload).SetResult(&out), http.MethodPost, url)
// multipart file upload
resp, err = r.Send(
r.R().
SetFileReader("avatar", "a.png", reader).
SetFormData(map[string]string{"user_id": "1"}),
http.MethodPost, url,
)
// form-urlencoded
resp, err = r.Send(
r.R().SetFormData(map[string]string{"grant_type": "client_credentials"}),
http.MethodPost, tokenURL,
)
// streaming a large response
resp, err = r.Send(r.R().SetDoNotParseResponse(true), http.MethodGet, fileURL)
defer resp.RawBody().Close()Interface
go
type IRequester interface {
R() *resty.Request // full go-resty builder, ctx-bound
Send(req *resty.Request, method, url string) (*resty.Response, IError) // execute → IError
WithContext(ctx context.Context) IRequester
Resty() *resty.Client // shared client — configure at startup
}Client-level configuration (retries, TLS, base URL, middleware)
Configure the shared resty client once at startup and wire it in:
go
rc := resty.New().
SetTimeout(10 * time.Second).
SetRetryCount(3).
SetBaseURL("https://api.example.com").
OnBeforeRequest(func(c *resty.Client, req *resty.Request) error { /* trace */ return nil })
app, _ := core.NewApp(env, core.WithRequester(core.NewRequesterWithClient(rc)))Then ctx.Requester() uses that client, still ctx-bound per request.
Custom timeout
go
bg, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
r := ctx.Requester().WithContext(bg)
r.Send(r.R(), http.MethodGet, url)