Implement API client functionality in the garm-cli
Signed-off-by: Mihaela Balutoiu <mbalutoiu@cloudbasesolutions.com>
This commit is contained in:
parent
851a9bd0ae
commit
ff5abf1294
35 changed files with 220 additions and 5661 deletions
|
|
@ -1,301 +0,0 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
apiParams "github.com/cloudbase/garm/apiserver/params"
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewClient(name string, cfg config.Manager, debug bool) *Client {
|
||||
cli := resty.New()
|
||||
if cfg.Token != "" {
|
||||
cli = cli.SetAuthToken(cfg.Token)
|
||||
}
|
||||
cli = cli.
|
||||
SetHeader("Accept", "application/json").
|
||||
SetDebug(debug)
|
||||
return &Client{
|
||||
ManagerName: name,
|
||||
Config: cfg,
|
||||
client: cli,
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
ManagerName string
|
||||
Config config.Manager
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (c *Client) handleError(err error, resp *resty.Response) error {
|
||||
var ret error
|
||||
if err != nil {
|
||||
ret = fmt.Errorf("request returned error: %s", err)
|
||||
}
|
||||
|
||||
if resp != nil && resp.IsError() {
|
||||
body := resp.Body()
|
||||
if len(body) > 0 {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr == nil {
|
||||
ret = fmt.Errorf("API returned error: %s", apiErr.Details)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *Client) decodeAPIError(body []byte) (apiParams.APIErrorResponse, error) {
|
||||
var errDetails apiParams.APIErrorResponse
|
||||
if err := json.Unmarshal(body, &errDetails); err != nil {
|
||||
return apiParams.APIErrorResponse{}, fmt.Errorf("invalid response from server, use --debug for more info")
|
||||
}
|
||||
|
||||
return errDetails, fmt.Errorf("error in API call: %s", errDetails.Details)
|
||||
}
|
||||
|
||||
func (c *Client) InitManager(url string, param params.NewUserParams) (params.User, error) {
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return params.User{}, errors.Wrap(err, "marshaling body")
|
||||
}
|
||||
url = fmt.Sprintf("%s/api/v1/first-run/", url)
|
||||
|
||||
var response params.User
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return params.User{}, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return params.User{}, fmt.Errorf("error running init: %s", apiErr.Details)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) Login(url string, param params.PasswordLoginParams) (string, error) {
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "marshaling body")
|
||||
}
|
||||
url = fmt.Sprintf("%s/api/v1/auth/login", url)
|
||||
|
||||
var response params.JWTResponse
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return "", errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return "", fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
|
||||
return response.Token, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListCredentials() ([]params.GithubCredentials, error) {
|
||||
var ghCreds []params.GithubCredentials
|
||||
url := fmt.Sprintf("%s/api/v1/credentials", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&ghCreds).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return nil, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return nil, fmt.Errorf("error fetching credentials: %s", apiErr.Details)
|
||||
}
|
||||
return ghCreds, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListProviders() ([]params.Provider, error) {
|
||||
var providers []params.Provider
|
||||
url := fmt.Sprintf("%s/api/v1/providers", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&providers).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return nil, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return nil, fmt.Errorf("error fetching providers: %s", apiErr.Details)
|
||||
}
|
||||
return providers, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetInstanceByName(instanceName string) (params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/instances/%s", c.Config.BaseURL, instanceName)
|
||||
|
||||
var response params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteRunner(instanceName string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/instances/%s", c.Config.BaseURL, instanceName)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error deleting runner: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllJobs() ([]params.Job, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/jobs", c.Config.BaseURL)
|
||||
|
||||
var response []params.Job
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
return response, c.handleError(err, resp)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListPoolInstances(poolID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s/instances", c.Config.BaseURL, poolID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllInstances() ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/instances", c.Config.BaseURL)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetPoolByID(poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllPools() ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools", c.Config.BaseURL)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeletePoolByID(poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return fmt.Errorf("error deleting pool by ID: %s", apiErr.Details)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdatePoolByID(poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s", c.Config.BaseURL, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err != nil || resp.IsError() {
|
||||
apiErr, decErr := c.decodeAPIError(resp.Body())
|
||||
if decErr != nil {
|
||||
return response, errors.Wrap(decErr, "sending request")
|
||||
}
|
||||
return response, fmt.Errorf("error performing login: %s", apiErr.Details)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
func (c *Client) ListEnterprises() ([]params.Enterprise, error) {
|
||||
var enterprises []params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&enterprises).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enterprises, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateEnterprise(param params.CreateEnterpriseParams) (params.Enterprise, error) {
|
||||
var response params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises", c.Config.BaseURL)
|
||||
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return params.Enterprise{}, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Enterprise{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateEnterprise(enterpriseID string, param params.UpdateEntityParams) (params.Enterprise, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response params.Enterprise
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Enterprise{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetEnterprise(enterpriseID string) (params.Enterprise, error) {
|
||||
var response params.Enterprise
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Enterprise{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteEnterprise(enterpriseID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s", c.Config.BaseURL, enterpriseID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateEnterprisePool(enterpriseID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListEnterprisePools(enterpriseID string) ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetEnterprisePool(enterpriseID, poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteEnterprisePool(enterpriseID, poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateEnterprisePool(enterpriseID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/pools/%s", c.Config.BaseURL, enterpriseID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListEnterpriseInstances(enterpriseID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/enterprises/%s/instances", c.Config.BaseURL, enterpriseID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
func (c *Client) ListOrganizations() ([]params.Organization, error) {
|
||||
var orgs []params.Organization
|
||||
url := fmt.Sprintf("%s/api/v1/organizations", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&orgs).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return orgs, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateOrganization(param params.CreateOrgParams) (params.Organization, error) {
|
||||
var response params.Organization
|
||||
url := fmt.Sprintf("%s/api/v1/organizations", c.Config.BaseURL)
|
||||
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return params.Organization{}, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Organization{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateOrganization(orgID string, param params.UpdateEntityParams) (params.Organization, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s", c.Config.BaseURL, orgID)
|
||||
|
||||
var response params.Organization
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Organization{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetOrganization(orgID string) (params.Organization, error) {
|
||||
var response params.Organization
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s", c.Config.BaseURL, orgID)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Organization{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteOrganization(orgID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s", c.Config.BaseURL, orgID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateOrgPool(orgID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/pools", c.Config.BaseURL, orgID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListOrgPools(orgID string) ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/pools", c.Config.BaseURL, orgID)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetOrgPool(orgID, poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/pools/%s", c.Config.BaseURL, orgID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteOrgPool(orgID, poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/pools/%s", c.Config.BaseURL, orgID, poolID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateOrgPool(orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/pools/%s", c.Config.BaseURL, orgID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListOrgInstances(orgID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/organizations/%s/instances", c.Config.BaseURL, orgID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateMetricsToken() (string, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/metrics-token", c.Config.BaseURL)
|
||||
|
||||
type response struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
var t response
|
||||
resp, err := c.client.R().
|
||||
SetResult(&t).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return t.Token, nil
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2022 Cloudbase Solutions SRL
|
||||
//
|
||||
// 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.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
func (c *Client) ListRepositories() ([]params.Repository, error) {
|
||||
var repos []params.Repository
|
||||
url := fmt.Sprintf("%s/api/v1/repositories", c.Config.BaseURL)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&repos).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateRepository(param params.CreateRepoParams) (params.Repository, error) {
|
||||
var response params.Repository
|
||||
url := fmt.Sprintf("%s/api/v1/repositories", c.Config.BaseURL)
|
||||
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return params.Repository{}, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Repository{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetRepository(repoID string) (params.Repository, error) {
|
||||
var response params.Repository
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s", c.Config.BaseURL, repoID)
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Repository{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteRepository(repoID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s", c.Config.BaseURL, repoID)
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateRepoPool(repoID string, param params.CreatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/pools", c.Config.BaseURL, repoID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Post(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListRepoPools(repoID string) ([]params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/pools", c.Config.BaseURL, repoID)
|
||||
|
||||
var response []params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetRepoPool(repoID, poolID string) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/pools/%s", c.Config.BaseURL, repoID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteRepoPool(repoID, poolID string) error {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/pools/%s", c.Config.BaseURL, repoID, poolID)
|
||||
|
||||
resp, err := c.client.R().
|
||||
Delete(url)
|
||||
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateRepoPool(repoID, poolID string, param params.UpdatePoolParams) (params.Pool, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/pools/%s", c.Config.BaseURL, repoID, poolID)
|
||||
|
||||
var response params.Pool
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Pool{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateRepo(repoID string, param params.UpdateEntityParams) (params.Repository, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s", c.Config.BaseURL, repoID)
|
||||
|
||||
var response params.Repository
|
||||
body, err := json.Marshal(param)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := c.client.R().
|
||||
SetBody(body).
|
||||
SetResult(&response).
|
||||
Put(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return params.Repository{}, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListRepoInstances(repoID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/repositories/%s/instances", c.Config.BaseURL, repoID)
|
||||
|
||||
var response []params.Instance
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err := c.handleError(err, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientCreds "github.com/cloudbase/garm/client/credentials"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -50,11 +51,12 @@ func init() {
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
creds, err := cli.ListCredentials()
|
||||
listCredsReq := apiClientCreds.NewListCredentialsParams()
|
||||
response, err := apiCli.Credentials.ListCredentials(listCredsReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatGithubCredentials(creds)
|
||||
formatGithubCredentials(response.Payload)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -54,16 +55,17 @@ var enterpriseAddCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newEnterpriseReq := params.CreateEnterpriseParams{
|
||||
newEnterpriseReq := apiClientEnterprises.NewCreateEnterpriseParams()
|
||||
newEnterpriseReq.Body = params.CreateEnterpriseParams{
|
||||
Name: enterpriseName,
|
||||
WebhookSecret: enterpriseWebhookSecret,
|
||||
CredentialsName: enterpriseCreds,
|
||||
}
|
||||
enterprise, err := cli.CreateEnterprise(newEnterpriseReq)
|
||||
response, err := apiCli.Enterprises.CreateEnterprise(newEnterpriseReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneEnterprise(enterprise)
|
||||
formatOneEnterprise(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -79,11 +81,12 @@ var enterpriseListCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
enterprises, err := cli.ListEnterprises()
|
||||
listEnterprisesReq := apiClientEnterprises.NewListEnterprisesParams()
|
||||
response, err := apiCli.Enterprises.ListEnterprises(listEnterprisesReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatEnterprises(enterprises)
|
||||
formatEnterprises(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -103,11 +106,13 @@ var enterpriseShowCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
enterprise, err := cli.GetEnterprise(args[0])
|
||||
showEnterpriseReq := apiClientEnterprises.NewGetEnterpriseParams()
|
||||
showEnterpriseReq.EnterpriseID = args[0]
|
||||
response, err := apiCli.Enterprises.GetEnterprise(showEnterpriseReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneEnterprise(enterprise)
|
||||
formatOneEnterprise(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -128,7 +133,9 @@ var enterpriseDeleteCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteEnterprise(args[0]); err != nil {
|
||||
deleteEnterpriseReq := apiClientEnterprises.NewDeleteEnterpriseParams()
|
||||
deleteEnterpriseReq.EnterpriseID = args[0]
|
||||
if err := apiCli.Enterprises.DeleteEnterprise(deleteEnterpriseReq, authToken); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
@ -152,16 +159,17 @@ var enterpriseUpdateCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
enterpriseUpdateReq := params.UpdateEntityParams{
|
||||
updateEnterpriseReq := apiClientEnterprises.NewUpdateEnterpriseParams()
|
||||
updateEnterpriseReq.Body = params.UpdateEntityParams{
|
||||
WebhookSecret: repoWebhookSecret,
|
||||
CredentialsName: repoCreds,
|
||||
}
|
||||
enterprise, err := cli.UpdateEnterprise(args[0], enterpriseUpdateReq)
|
||||
updateEnterpriseReq.EnterpriseID = args[0]
|
||||
response, err := apiCli.Enterprises.UpdateEnterprise(updateEnterpriseReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneEnterprise(enterprise)
|
||||
formatOneEnterprise(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import (
|
|||
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
apiClientFirstRun "github.com/cloudbase/garm/client/first_run"
|
||||
apiClientLogin "github.com/cloudbase/garm/client/login"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -54,7 +56,8 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
|
|||
return err
|
||||
}
|
||||
|
||||
newUser := params.NewUserParams{
|
||||
newUserReq := apiClientFirstRun.NewFirstRunParams()
|
||||
newUserReq.Body = params.NewUserParams{
|
||||
Username: loginUserName,
|
||||
Password: loginPassword,
|
||||
FullName: loginFullName,
|
||||
|
|
@ -62,17 +65,21 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
|
|||
}
|
||||
|
||||
url := strings.TrimSuffix(loginURL, "/")
|
||||
response, err := cli.InitManager(url, newUser)
|
||||
|
||||
initApiClient(url, "")
|
||||
|
||||
response, err := apiCli.FirstRun.FirstRun(newUserReq, authToken)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initializing manager")
|
||||
}
|
||||
|
||||
loginParams := params.PasswordLoginParams{
|
||||
newLoginParamsReq := apiClientLogin.NewLoginParams()
|
||||
newLoginParamsReq.Body = params.PasswordLoginParams{
|
||||
Username: loginUserName,
|
||||
Password: loginPassword,
|
||||
}
|
||||
|
||||
token, err := cli.Login(url, loginParams)
|
||||
token, err := apiCli.Login.Login(newLoginParamsReq, authToken)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "authenticating")
|
||||
}
|
||||
|
|
@ -80,7 +87,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
|
|||
cfg.Managers = append(cfg.Managers, config.Manager{
|
||||
Name: loginProfileName,
|
||||
BaseURL: url,
|
||||
Token: token,
|
||||
Token: token.Payload.Token,
|
||||
})
|
||||
|
||||
cfg.ActiveManager = loginProfileName
|
||||
|
|
@ -89,7 +96,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
|
|||
return errors.Wrap(err, "saving config")
|
||||
}
|
||||
|
||||
renderUserTable(response)
|
||||
renderUserTable(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
apiClientJobs "github.com/cloudbase/garm/client/jobs"
|
||||
"github.com/cloudbase/garm/params"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -44,11 +45,12 @@ var jobsListCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
jobs, err := cli.ListAllJobs()
|
||||
listJobsReq := apiClientJobs.NewListJobsParams()
|
||||
response, err := apiCli.Jobs.ListJobs(listJobsReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatJobs(jobs)
|
||||
formatJobs(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientMetricToken "github.com/cloudbase/garm/client/metrics_token"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -39,11 +40,12 @@ var metricsTokenCreateCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
token, err := cli.CreateMetricsToken()
|
||||
showMetricsTokenReq := apiClientMetricToken.NewGetMetricsTokenParams()
|
||||
response, err := apiCli.MetricsToken.GetMetricsToken(showMetricsTokenReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(token)
|
||||
fmt.Println(response.Payload.Token)
|
||||
|
||||
return nil
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -54,16 +55,17 @@ var orgAddCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newOrgReq := params.CreateOrgParams{
|
||||
newOrgReq := apiClientOrgs.NewCreateOrgParams()
|
||||
newOrgReq.Body = params.CreateOrgParams{
|
||||
Name: orgName,
|
||||
WebhookSecret: orgWebhookSecret,
|
||||
CredentialsName: orgCreds,
|
||||
}
|
||||
org, err := cli.CreateOrganization(newOrgReq)
|
||||
response, err := apiCli.Organizations.CreateOrg(newOrgReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneOrganization(org)
|
||||
formatOneOrganization(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -85,16 +87,17 @@ var orgUpdateCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
orgUpdateReq := params.UpdateEntityParams{
|
||||
updateOrgReq := apiClientOrgs.NewUpdateOrgParams()
|
||||
updateOrgReq.Body = params.UpdateEntityParams{
|
||||
WebhookSecret: repoWebhookSecret,
|
||||
CredentialsName: orgCreds,
|
||||
}
|
||||
org, err := cli.UpdateOrganization(args[0], orgUpdateReq)
|
||||
updateOrgReq.OrgID = args[0]
|
||||
response, err := apiCli.Organizations.UpdateOrg(updateOrgReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneOrganization(org)
|
||||
formatOneOrganization(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -110,11 +113,12 @@ var orgListCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
orgs, err := cli.ListOrganizations()
|
||||
listOrgsReq := apiClientOrgs.NewListOrgsParams()
|
||||
response, err := apiCli.Organizations.ListOrgs(listOrgsReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOrganizations(orgs)
|
||||
formatOrganizations(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -134,11 +138,13 @@ var orgShowCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
org, err := cli.GetOrganization(args[0])
|
||||
showOrgReq := apiClientOrgs.NewGetOrgParams()
|
||||
showOrgReq.OrgID = args[0]
|
||||
response, err := apiCli.Organizations.GetOrg(showOrgReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneOrganization(org)
|
||||
formatOneOrganization(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -159,7 +165,9 @@ var orgDeleteCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteOrganization(args[0]); err != nil {
|
||||
deleteOrgReq := apiClientOrgs.NewDeleteOrgParams()
|
||||
deleteOrgReq.OrgID = args[0]
|
||||
if err := apiCli.Organizations.DeleteOrg(deleteOrgReq, authToken); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
|
||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||
apiClientPools "github.com/cloudbase/garm/client/pools"
|
||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -96,13 +101,28 @@ Example:
|
|||
switch len(args) {
|
||||
case 0:
|
||||
if cmd.Flags().Changed("repo") {
|
||||
pools, err = cli.ListRepoPools(poolRepository)
|
||||
var response *apiClientRepos.ListRepoPoolsOK
|
||||
listRepoPoolsReq := apiClientRepos.NewListRepoPoolsParams()
|
||||
listRepoPoolsReq.RepoID = poolRepository
|
||||
response, err = apiCli.Repositories.ListRepoPools(listRepoPoolsReq, authToken)
|
||||
pools = response.Payload
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pools, err = cli.ListOrgPools(poolOrganization)
|
||||
var response *apiClientOrgs.ListOrgPoolsOK
|
||||
listOrgPoolsReq := apiClientOrgs.NewListOrgPoolsParams()
|
||||
listOrgPoolsReq.OrgID = poolOrganization
|
||||
response, err = apiCli.Organizations.ListOrgPools(listOrgPoolsReq, authToken)
|
||||
pools = response.Payload
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
pools, err = cli.ListEnterprisePools(poolEnterprise)
|
||||
var response *apiClientEnterprises.ListEnterprisePoolsOK
|
||||
listEnterprisePoolsReq := apiClientEnterprises.NewListEnterprisePoolsParams()
|
||||
listEnterprisePoolsReq.EnterpriseID = poolEnterprise
|
||||
response, err = apiCli.Enterprises.ListEnterprisePools(listEnterprisePoolsReq, authToken)
|
||||
pools = response.Payload
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
pools, err = cli.ListAllPools()
|
||||
var response *apiClientPools.ListPoolsOK
|
||||
listPoolsReq := apiClientPools.NewListPoolsParams()
|
||||
response, err = apiCli.Pools.ListPools(listPoolsReq, authToken)
|
||||
pools = response.Payload
|
||||
} else {
|
||||
cmd.Help() //nolint
|
||||
os.Exit(0)
|
||||
|
|
@ -138,11 +158,13 @@ var poolShowCmd = &cobra.Command{
|
|||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
pool, err := cli.GetPoolByID(args[0])
|
||||
getPoolReq := apiClientPools.NewGetPoolParams()
|
||||
getPoolReq.PoolID = args[0]
|
||||
response, err := apiCli.Pools.GetPool(getPoolReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOnePool(pool)
|
||||
formatOnePool(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -166,7 +188,9 @@ var poolDeleteCmd = &cobra.Command{
|
|||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
if err := cli.DeletePoolByID(args[0]); err != nil {
|
||||
deletePoolReq := apiClientPools.NewDeletePoolParams()
|
||||
deletePoolReq.PoolID = args[0]
|
||||
if err := apiCli.Pools.DeletePool(deletePoolReq, authToken); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
@ -226,11 +250,26 @@ var poolAddCmd = &cobra.Command{
|
|||
var err error
|
||||
|
||||
if cmd.Flags().Changed("repo") {
|
||||
pool, err = cli.CreateRepoPool(poolRepository, newPoolParams)
|
||||
var response *apiClientRepos.CreateRepoPoolOK
|
||||
newRepoPoolReq := apiClientRepos.NewCreateRepoPoolParams()
|
||||
newRepoPoolReq.RepoID = poolRepository
|
||||
newRepoPoolReq.Body = newPoolParams
|
||||
response, err = apiCli.Repositories.CreateRepoPool(newRepoPoolReq, authToken)
|
||||
pool = response.Payload
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
pool, err = cli.CreateOrgPool(poolOrganization, newPoolParams)
|
||||
var response *apiClientOrgs.CreateOrgPoolOK
|
||||
newOrgPoolReq := apiClientOrgs.NewCreateOrgPoolParams()
|
||||
newOrgPoolReq.OrgID = poolOrganization
|
||||
newOrgPoolReq.Body = newPoolParams
|
||||
response, err = apiCli.Organizations.CreateOrgPool(newOrgPoolReq, authToken)
|
||||
pool = response.Payload
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
pool, err = cli.CreateEnterprisePool(poolEnterprise, newPoolParams)
|
||||
var response *apiClientEnterprises.CreateEnterprisePoolOK
|
||||
newEnterprisePoolReq := apiClientEnterprises.NewCreateEnterprisePoolParams()
|
||||
newEnterprisePoolReq.EnterpriseID = poolEnterprise
|
||||
newEnterprisePoolReq.Body = newPoolParams
|
||||
response, err = apiCli.Enterprises.CreateEnterprisePool(newEnterprisePoolReq, authToken)
|
||||
pool = response.Payload
|
||||
} else {
|
||||
cmd.Help() //nolint
|
||||
os.Exit(0)
|
||||
|
|
@ -267,6 +306,7 @@ explicitly remove them using the runner delete command.
|
|||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
updatePoolReq := apiClientPools.NewUpdatePoolParams()
|
||||
poolUpdateParams := params.UpdatePoolParams{}
|
||||
|
||||
if cmd.Flags().Changed("image") {
|
||||
|
|
@ -331,12 +371,14 @@ explicitly remove them using the runner delete command.
|
|||
poolUpdateParams.ExtraSpecs = data
|
||||
}
|
||||
|
||||
pool, err := cli.UpdatePoolByID(args[0], poolUpdateParams)
|
||||
updatePoolReq.PoolID = args[0]
|
||||
updatePoolReq.Body = poolUpdateParams
|
||||
response, err := apiCli.Pools.UpdatePool(updatePoolReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
formatOnePool(pool)
|
||||
formatOnePool(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
apiClientLogin "github.com/cloudbase/garm/client/login"
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
|
@ -143,12 +144,15 @@ var profileAddCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
url := strings.TrimSuffix(loginURL, "/")
|
||||
loginParams := params.PasswordLoginParams{
|
||||
|
||||
initApiClient(url, "")
|
||||
|
||||
newLoginParamsReq := apiClientLogin.NewLoginParams()
|
||||
newLoginParamsReq.Body = params.PasswordLoginParams{
|
||||
Username: loginUserName,
|
||||
Password: loginPassword,
|
||||
}
|
||||
|
||||
resp, err := cli.Login(url, loginParams)
|
||||
resp, err := apiCli.Login.Login(newLoginParamsReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -156,7 +160,7 @@ var profileAddCmd = &cobra.Command{
|
|||
cfg.Managers = append(cfg.Managers, config.Manager{
|
||||
Name: loginProfileName,
|
||||
BaseURL: url,
|
||||
Token: resp,
|
||||
Token: resp.Payload.Token,
|
||||
})
|
||||
cfg.ActiveManager = loginProfileName
|
||||
|
||||
|
|
@ -190,16 +194,17 @@ installation, by performing a login.
|
|||
return err
|
||||
}
|
||||
|
||||
loginParams := params.PasswordLoginParams{
|
||||
newLoginParamsReq := apiClientLogin.NewLoginParams()
|
||||
newLoginParamsReq.Body = params.PasswordLoginParams{
|
||||
Username: loginUserName,
|
||||
Password: loginPassword,
|
||||
}
|
||||
|
||||
resp, err := cli.Login(mgr.BaseURL, loginParams)
|
||||
resp, err := apiCli.Login.Login(newLoginParamsReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.SetManagerToken(mgr.Name, resp); err != nil {
|
||||
if err := cfg.SetManagerToken(mgr.Name, resp.Payload.Token); err != nil {
|
||||
return fmt.Errorf("error saving new token: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientProviders "github.com/cloudbase/garm/client/providers"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -49,11 +50,12 @@ func init() {
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
providers, err := cli.ListProviders()
|
||||
listProvidersReq := apiClientProviders.NewListProvidersParams()
|
||||
response, err := apiCli.Providers.ListProviders(listProvidersReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatProviders(providers)
|
||||
formatProviders(response.Payload)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
|
|
@ -55,17 +56,18 @@ var repoAddCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
newRepoReq := params.CreateRepoParams{
|
||||
newRepoReq := apiClientRepos.NewCreateRepoParams()
|
||||
newRepoReq.Body = params.CreateRepoParams{
|
||||
Owner: repoOwner,
|
||||
Name: repoName,
|
||||
WebhookSecret: repoWebhookSecret,
|
||||
CredentialsName: repoCreds,
|
||||
}
|
||||
repo, err := cli.CreateRepository(newRepoReq)
|
||||
response, err := apiCli.Repositories.CreateRepo(newRepoReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneRepository(repo)
|
||||
formatOneRepository(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -81,11 +83,12 @@ var repoListCmd = &cobra.Command{
|
|||
return errNeedsInitError
|
||||
}
|
||||
|
||||
repos, err := cli.ListRepositories()
|
||||
listReposReq := apiClientRepos.NewListReposParams()
|
||||
response, err := apiCli.Repositories.ListRepos(listReposReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatRepositories(repos)
|
||||
formatRepositories(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -107,16 +110,18 @@ var repoUpdateCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
repoUpdateReq := params.UpdateEntityParams{
|
||||
updateReposReq := apiClientRepos.NewUpdateRepoParams()
|
||||
updateReposReq.Body = params.UpdateEntityParams{
|
||||
WebhookSecret: repoWebhookSecret,
|
||||
CredentialsName: repoCreds,
|
||||
}
|
||||
repo, err := cli.UpdateRepo(args[0], repoUpdateReq)
|
||||
updateReposReq.RepoID = args[0]
|
||||
|
||||
response, err := apiCli.Repositories.UpdateRepo(updateReposReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneRepository(repo)
|
||||
formatOneRepository(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -136,11 +141,13 @@ var repoShowCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
repo, err := cli.GetRepository(args[0])
|
||||
showRepoReq := apiClientRepos.NewGetRepoParams()
|
||||
showRepoReq.RepoID = args[0]
|
||||
response, err := apiCli.Repositories.GetRepo(showRepoReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneRepository(repo)
|
||||
formatOneRepository(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -161,7 +168,9 @@ var repoDeleteCmd = &cobra.Command{
|
|||
if len(args) > 1 {
|
||||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
if err := cli.DeleteRepository(args[0]); err != nil {
|
||||
deleteRepoReq := apiClientRepos.NewDeleteRepoParams()
|
||||
deleteRepoReq.RepoID = args[0]
|
||||
if err := apiCli.Repositories.DeleteRepo(deleteRepoReq, authToken); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -16,11 +16,14 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/client"
|
||||
apiClient "github.com/cloudbase/garm/client"
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/config"
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
openapiRuntimeClient "github.com/go-openapi/runtime/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -29,8 +32,8 @@ var Version string
|
|||
var (
|
||||
cfg *config.Config
|
||||
mgr config.Manager
|
||||
cli *client.Client
|
||||
active string
|
||||
apiCli *apiClient.GarmAPI
|
||||
authToken runtime.ClientAuthInfoWriter
|
||||
needsInit bool
|
||||
debug bool
|
||||
errNeedsInitError = fmt.Errorf("please log into a garm installation first")
|
||||
|
|
@ -55,6 +58,28 @@ func Execute() {
|
|||
}
|
||||
}
|
||||
|
||||
func initApiClient(baseUrl, token string) {
|
||||
baseUrlParsed, err := url.Parse(baseUrl)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse base url %s: %s", baseUrl, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
apiPath, err := url.JoinPath(baseUrlParsed.Path, apiClient.DefaultBasePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to join base url path %s with %s: %s", baseUrlParsed.Path, apiClient.DefaultBasePath, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if debug {
|
||||
os.Setenv("SWAGGER_DEBUG", "true")
|
||||
}
|
||||
transportCfg := apiClient.DefaultTransportConfig().
|
||||
WithHost(baseUrlParsed.Host).
|
||||
WithBasePath(apiPath).
|
||||
WithSchemes([]string{baseUrlParsed.Scheme})
|
||||
apiCli = apiClient.NewHTTPClientWithConfig(nil, transportCfg)
|
||||
authToken = openapiRuntimeClient.BearerToken(token)
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
var err error
|
||||
cfg, err = config.LoadConfig()
|
||||
|
|
@ -70,7 +95,6 @@ func initConfig() {
|
|||
if err != nil {
|
||||
mgr = cfg.Managers[0]
|
||||
}
|
||||
active = mgr.Name
|
||||
}
|
||||
cli = client.NewClient(active, mgr, debug)
|
||||
initApiClient(mgr.BaseURL, mgr.Token)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ import (
|
|||
|
||||
"github.com/cloudbase/garm/params"
|
||||
|
||||
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
|
||||
apiClientInstances "github.com/cloudbase/garm/client/instances"
|
||||
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
|
||||
apiClientRepos "github.com/cloudbase/garm/client/repositories"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -88,16 +92,35 @@ Example:
|
|||
|
||||
return fmt.Errorf("specifying a pool ID and any of [all org repo enterprise] are mutually exclusive")
|
||||
}
|
||||
instances, err = cli.ListPoolInstances(args[0])
|
||||
var response *apiClientInstances.ListPoolInstancesOK
|
||||
listPoolInstancesReq := apiClientInstances.NewListPoolInstancesParams()
|
||||
listPoolInstancesReq.PoolID = args[0]
|
||||
response, err = apiCli.Instances.ListPoolInstances(listPoolInstancesReq, authToken)
|
||||
instances = response.Payload
|
||||
case 0:
|
||||
if cmd.Flags().Changed("repo") {
|
||||
instances, err = cli.ListRepoInstances(runnerRepository)
|
||||
var response *apiClientRepos.ListRepoInstancesOK
|
||||
listRepoInstancesReq := apiClientRepos.NewListRepoInstancesParams()
|
||||
listRepoInstancesReq.RepoID = runnerRepository
|
||||
response, err = apiCli.Repositories.ListRepoInstances(listRepoInstancesReq, authToken)
|
||||
instances = response.Payload
|
||||
} else if cmd.Flags().Changed("org") {
|
||||
instances, err = cli.ListOrgInstances(runnerOrganization)
|
||||
var response *apiClientOrgs.ListOrgInstancesOK
|
||||
listOrgInstancesReq := apiClientOrgs.NewListOrgInstancesParams()
|
||||
listOrgInstancesReq.OrgID = runnerOrganization
|
||||
response, err = apiCli.Organizations.ListOrgInstances(listOrgInstancesReq, authToken)
|
||||
instances = response.Payload
|
||||
} else if cmd.Flags().Changed("enterprise") {
|
||||
instances, err = cli.ListEnterpriseInstances(runnerEnterprise)
|
||||
var response *apiClientEnterprises.ListEnterpriseInstancesOK
|
||||
listEnterpriseInstancesReq := apiClientEnterprises.NewListEnterpriseInstancesParams()
|
||||
listEnterpriseInstancesReq.EnterpriseID = runnerEnterprise
|
||||
response, err = apiCli.Enterprises.ListEnterpriseInstances(listEnterpriseInstancesReq, authToken)
|
||||
instances = response.Payload
|
||||
} else if cmd.Flags().Changed("all") {
|
||||
instances, err = cli.ListAllInstances()
|
||||
var response *apiClientInstances.ListInstancesOK
|
||||
listInstancesReq := apiClientInstances.NewListInstancesParams()
|
||||
response, err = apiCli.Instances.ListInstances(listInstancesReq, authToken)
|
||||
instances = response.Payload
|
||||
} else {
|
||||
cmd.Help() //nolint
|
||||
os.Exit(0)
|
||||
|
|
@ -133,11 +156,13 @@ var runnerShowCmd = &cobra.Command{
|
|||
return fmt.Errorf("too many arguments")
|
||||
}
|
||||
|
||||
instance, err := cli.GetInstanceByName(args[0])
|
||||
showInstanceReq := apiClientInstances.NewGetInstanceParams()
|
||||
showInstanceReq.InstanceName = args[0]
|
||||
response, err := apiCli.Instances.GetInstance(showInstanceReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatSingleInstance(instance)
|
||||
formatSingleInstance(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
@ -170,7 +195,9 @@ to either cancel the workflow or wait for it to finish.
|
|||
return fmt.Errorf("use --force-remove-runner=true to remove a runner")
|
||||
}
|
||||
|
||||
if err := cli.DeleteRunner(args[0]); err != nil {
|
||||
deleteInstanceReq := apiClientInstances.NewDeleteInstanceParams()
|
||||
deleteInstanceReq.InstanceName = args[0]
|
||||
if err := apiCli.Instances.DeleteInstance(deleteInstanceReq, authToken); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -8,7 +8,6 @@ require (
|
|||
github.com/go-openapi/errors v0.20.4
|
||||
github.com/go-openapi/runtime v0.26.0
|
||||
github.com/go-openapi/strfmt v0.21.7
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/go-github/v53 v53.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
|
|
|
|||
3
go.sum
3
go.sum
|
|
@ -92,8 +92,6 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB
|
|||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
|
||||
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
|
||||
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
|
||||
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
|
|
@ -369,7 +367,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
|
|
|
|||
30
vendor/github.com/go-resty/resty/v2/.gitignore
generated
vendored
30
vendor/github.com/go-resty/resty/v2/.gitignore
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
coverage.out
|
||||
coverage.txt
|
||||
|
||||
# Exclude intellij IDE folders
|
||||
.idea/*
|
||||
48
vendor/github.com/go-resty/resty/v2/BUILD.bazel
generated
vendored
48
vendor/github.com/go-resty/resty/v2/BUILD.bazel
generated
vendored
|
|
@ -1,48 +0,0 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
load("@bazel_gazelle//:def.bzl", "gazelle")
|
||||
|
||||
# gazelle:prefix github.com/go-resty/resty/v2
|
||||
# gazelle:go_naming_convention import_alias
|
||||
gazelle(name = "gazelle")
|
||||
|
||||
go_library(
|
||||
name = "resty",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"middleware.go",
|
||||
"redirect.go",
|
||||
"request.go",
|
||||
"response.go",
|
||||
"resty.go",
|
||||
"retry.go",
|
||||
"trace.go",
|
||||
"transport.go",
|
||||
"transport112.go",
|
||||
"util.go",
|
||||
],
|
||||
importpath = "github.com/go-resty/resty/v2",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@org_golang_x_net//publicsuffix:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "resty_test",
|
||||
srcs = [
|
||||
"client_test.go",
|
||||
"context_test.go",
|
||||
"example_test.go",
|
||||
"request_test.go",
|
||||
"resty_test.go",
|
||||
"retry_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
data = glob([".testdata/*"]),
|
||||
embed = [":resty"],
|
||||
deps = ["@org_golang_x_net//proxy:go_default_library"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "go_default_library",
|
||||
actual = ":resty",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
21
vendor/github.com/go-resty/resty/v2/LICENSE
generated
vendored
21
vendor/github.com/go-resty/resty/v2/LICENSE
generated
vendored
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2021 Jeevanandam M., https://myjeeva.com <jeeva@myjeeva.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
906
vendor/github.com/go-resty/resty/v2/README.md
generated
vendored
906
vendor/github.com/go-resty/resty/v2/README.md
generated
vendored
|
|
@ -1,906 +0,0 @@
|
|||
<p align="center">
|
||||
<h1 align="center">Resty</h1>
|
||||
<p align="center">Simple HTTP and REST client library for Go (inspired by Ruby rest-client)</p>
|
||||
<p align="center"><a href="#features">Features</a> section describes in detail about Resty capabilities</p>
|
||||
</p>
|
||||
<p align="center">
|
||||
<p align="center"><a href="https://github.com/go-resty/resty/actions/workflows/ci.yml?query=branch%3Amaster"><img src="https://github.com/go-resty/resty/actions/workflows/ci.yml/badge.svg" alt="Build Status"></a> <a href="https://codecov.io/gh/go-resty/resty/branch/master"><img src="https://codecov.io/gh/go-resty/resty/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/go-resty/resty"><img src="https://goreportcard.com/badge/go-resty/resty" alt="Go Report Card"></a> <a href="https://github.com/go-resty/resty/releases/latest"><img src="https://img.shields.io/badge/version-2.7.0-blue.svg" alt="Release Version"></a> <a href="https://pkg.go.dev/github.com/go-resty/resty/v2"><img src="https://pkg.go.dev/badge/github.com/go-resty/resty" alt="GoDoc"></a> <a href="LICENSE"><img src="https://img.shields.io/github/license/go-resty/resty.svg" alt="License"></a> <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a></p>
|
||||
</p>
|
||||
<p align="center">
|
||||
<h4 align="center">Resty Communication Channels</h4>
|
||||
<p align="center"><a href="https://gitter.im/go_resty/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/go_resty/community.svg" alt="Chat on Gitter - Resty Community"></a> <a href="https://twitter.com/go_resty"><img src="https://img.shields.io/badge/twitter-@go__resty-55acee.svg" alt="Twitter @go_resty"></a></p>
|
||||
</p>
|
||||
|
||||
## News
|
||||
|
||||
* v2.7.0 [released](https://github.com/go-resty/resty/releases/tag/v2.7.0) and tagged on Nov 03, 2021.
|
||||
* v2.0.0 [released](https://github.com/go-resty/resty/releases/tag/v2.0.0) and tagged on Jul 16, 2019.
|
||||
* v1.12.0 [released](https://github.com/go-resty/resty/releases/tag/v1.12.0) and tagged on Feb 27, 2019.
|
||||
* v1.0 released and tagged on Sep 25, 2017. - Resty's first version was released on Sep 15, 2015 then it grew gradually as a very handy and helpful library. Its been a two years since first release. I'm very thankful to Resty users and its [contributors](https://github.com/go-resty/resty/graphs/contributors).
|
||||
|
||||
## Features
|
||||
|
||||
* GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS, etc.
|
||||
* Simple and chainable methods for settings and request
|
||||
* [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request) Body can be `string`, `[]byte`, `struct`, `map`, `slice` and `io.Reader` too
|
||||
* Auto detects `Content-Type`
|
||||
* Buffer less processing for `io.Reader`
|
||||
* Native `*http.Request` instance may be accessed during middleware and request execution via `Request.RawRequest`
|
||||
* Request Body can be read multiple times via `Request.RawRequest.GetBody()`
|
||||
* [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#Response) object gives you more possibility
|
||||
* Access as `[]byte` array - `response.Body()` OR Access as `string` - `response.String()`
|
||||
* Know your `response.Time()` and when we `response.ReceivedAt()`
|
||||
* Automatic marshal and unmarshal for `JSON` and `XML` content type
|
||||
* Default is `JSON`, if you supply `struct/map` without header `Content-Type`
|
||||
* For auto-unmarshal, refer to -
|
||||
- Success scenario [Request.SetResult()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetResult) and [Response.Result()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Result).
|
||||
- Error scenario [Request.SetError()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetError) and [Response.Error()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Error).
|
||||
- Supports [RFC7807](https://tools.ietf.org/html/rfc7807) - `application/problem+json` & `application/problem+xml`
|
||||
* Resty provides an option to override [JSON Marshal/Unmarshal and XML Marshal/Unmarshal](#override-json--xml-marshalunmarshal)
|
||||
* Easy to upload one or more file(s) via `multipart/form-data`
|
||||
* Auto detects file content type
|
||||
* Request URL [Path Params (aka URI Params)](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetPathParams)
|
||||
* Backoff Retry Mechanism with retry condition function [reference](retry_test.go)
|
||||
* Resty client HTTP & REST [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnBeforeRequest) and [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnAfterResponse) middlewares
|
||||
* `Request.SetContext` supported
|
||||
* Authorization option of `BasicAuth` and `Bearer` token
|
||||
* Set request `ContentLength` value for all request or particular request
|
||||
* Custom [Root Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetRootCertificate) and Client [Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetCertificates)
|
||||
* Download/Save HTTP response directly into File, like `curl -o` flag. See [SetOutputDirectory](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetOutputDirectory) & [SetOutput](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetOutput).
|
||||
* Cookies for your request and CookieJar support
|
||||
* SRV Record based request instead of Host URL
|
||||
* Client settings like `Timeout`, `RedirectPolicy`, `Proxy`, `TLSClientConfig`, `Transport`, etc.
|
||||
* Optionally allows GET request with payload, see [SetAllowGetMethodPayload](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetAllowGetMethodPayload)
|
||||
* Supports registering external JSON library into resty, see [how to use](https://github.com/go-resty/resty/issues/76#issuecomment-314015250)
|
||||
* Exposes Response reader without reading response (no auto-unmarshaling) if need be, see [how to use](https://github.com/go-resty/resty/issues/87#issuecomment-322100604)
|
||||
* Option to specify expected `Content-Type` when response `Content-Type` header missing. Refer to [#92](https://github.com/go-resty/resty/issues/92)
|
||||
* Resty design
|
||||
* Have client level settings & options and also override at Request level if you want to
|
||||
* Request and Response middleware
|
||||
* Create Multiple clients if you want to `resty.New()`
|
||||
* Supports `http.RoundTripper` implementation, see [SetTransport](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetTransport)
|
||||
* goroutine concurrent safe
|
||||
* Resty Client trace, see [Client.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.EnableTrace) and [Request.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.EnableTrace)
|
||||
* Since v2.4.0, trace info contains a `RequestAttempt` value, and the `Request` object contains an `Attempt` attribute
|
||||
* Debug mode - clean and informative logging presentation
|
||||
* Gzip - Go does it automatically also resty has fallback handling too
|
||||
* Works fine with `HTTP/2` and `HTTP/1.1`
|
||||
* [Bazel support](#bazel-support)
|
||||
* Easily mock Resty for testing, [for e.g.](#mocking-http-requests-using-httpmock-library)
|
||||
* Well tested client library
|
||||
|
||||
### Included Batteries
|
||||
|
||||
* Redirect Policies - see [how to use](#redirect-policy)
|
||||
* NoRedirectPolicy
|
||||
* FlexibleRedirectPolicy
|
||||
* DomainCheckRedirectPolicy
|
||||
* etc. [more info](redirect.go)
|
||||
* Retry Mechanism [how to use](#retries)
|
||||
* Backoff Retry
|
||||
* Conditional Retry
|
||||
* Since v2.6.0, Retry Hooks - [Client](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.AddRetryHook), [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.AddRetryHook)
|
||||
* SRV Record based request instead of Host URL [how to use](resty_test.go#L1412)
|
||||
* etc (upcoming - throw your idea's [here](https://github.com/go-resty/resty/issues)).
|
||||
|
||||
|
||||
#### Supported Go Versions
|
||||
|
||||
Initially Resty started supporting `go modules` since `v1.10.0` release.
|
||||
|
||||
Starting Resty v2 and higher versions, it fully embraces [go modules](https://github.com/golang/go/wiki/Modules) package release. It requires a Go version capable of understanding `/vN` suffixed imports:
|
||||
|
||||
- 1.9.7+
|
||||
- 1.10.3+
|
||||
- 1.11+
|
||||
|
||||
|
||||
## It might be beneficial for your project :smile:
|
||||
|
||||
Resty author also published following projects for Go Community.
|
||||
|
||||
* [aah framework](https://aahframework.org) - A secure, flexible, rapid Go web framework.
|
||||
* [THUMBAI](https://thumbai.app) - Go Mod Repository, Go Vanity Service and Simple Proxy Server.
|
||||
* [go-model](https://github.com/jeevatkm/go-model) - Robust & Easy to use model mapper and utility methods for Go `struct`.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Go Modules
|
||||
require github.com/go-resty/resty/v2 v2.7.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The following samples will assist you to become as comfortable as possible with resty library.
|
||||
|
||||
```go
|
||||
// Import resty into your code and refer it as `resty`.
|
||||
import "github.com/go-resty/resty/v2"
|
||||
```
|
||||
|
||||
#### Simple GET
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.R().
|
||||
EnableTrace().
|
||||
Get("https://httpbin.org/get")
|
||||
|
||||
// Explore response object
|
||||
fmt.Println("Response Info:")
|
||||
fmt.Println(" Error :", err)
|
||||
fmt.Println(" Status Code:", resp.StatusCode())
|
||||
fmt.Println(" Status :", resp.Status())
|
||||
fmt.Println(" Proto :", resp.Proto())
|
||||
fmt.Println(" Time :", resp.Time())
|
||||
fmt.Println(" Received At:", resp.ReceivedAt())
|
||||
fmt.Println(" Body :\n", resp)
|
||||
fmt.Println()
|
||||
|
||||
// Explore trace info
|
||||
fmt.Println("Request Trace Info:")
|
||||
ti := resp.Request.TraceInfo()
|
||||
fmt.Println(" DNSLookup :", ti.DNSLookup)
|
||||
fmt.Println(" ConnTime :", ti.ConnTime)
|
||||
fmt.Println(" TCPConnTime :", ti.TCPConnTime)
|
||||
fmt.Println(" TLSHandshake :", ti.TLSHandshake)
|
||||
fmt.Println(" ServerTime :", ti.ServerTime)
|
||||
fmt.Println(" ResponseTime :", ti.ResponseTime)
|
||||
fmt.Println(" TotalTime :", ti.TotalTime)
|
||||
fmt.Println(" IsConnReused :", ti.IsConnReused)
|
||||
fmt.Println(" IsConnWasIdle :", ti.IsConnWasIdle)
|
||||
fmt.Println(" ConnIdleTime :", ti.ConnIdleTime)
|
||||
fmt.Println(" RequestAttempt:", ti.RequestAttempt)
|
||||
fmt.Println(" RemoteAddr :", ti.RemoteAddr.String())
|
||||
|
||||
/* Output
|
||||
Response Info:
|
||||
Error : <nil>
|
||||
Status Code: 200
|
||||
Status : 200 OK
|
||||
Proto : HTTP/2.0
|
||||
Time : 457.034718ms
|
||||
Received At: 2020-09-14 15:35:29.784681 -0700 PDT m=+0.458137045
|
||||
Body :
|
||||
{
|
||||
"args": {},
|
||||
"headers": {
|
||||
"Accept-Encoding": "gzip",
|
||||
"Host": "httpbin.org",
|
||||
"User-Agent": "go-resty/2.4.0 (https://github.com/go-resty/resty)",
|
||||
"X-Amzn-Trace-Id": "Root=1-5f5ff031-000ff6292204aa6898e4de49"
|
||||
},
|
||||
"origin": "0.0.0.0",
|
||||
"url": "https://httpbin.org/get"
|
||||
}
|
||||
|
||||
Request Trace Info:
|
||||
DNSLookup : 4.074657ms
|
||||
ConnTime : 381.709936ms
|
||||
TCPConnTime : 77.428048ms
|
||||
TLSHandshake : 299.623597ms
|
||||
ServerTime : 75.414703ms
|
||||
ResponseTime : 79.337µs
|
||||
TotalTime : 457.034718ms
|
||||
IsConnReused : false
|
||||
IsConnWasIdle : false
|
||||
ConnIdleTime : 0s
|
||||
RequestAttempt: 1
|
||||
RemoteAddr : 3.221.81.55:443
|
||||
*/
|
||||
```
|
||||
|
||||
#### Enhanced GET
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.R().
|
||||
SetQueryParams(map[string]string{
|
||||
"page_no": "1",
|
||||
"limit": "20",
|
||||
"sort":"name",
|
||||
"order": "asc",
|
||||
"random":strconv.FormatInt(time.Now().Unix(), 10),
|
||||
}).
|
||||
SetHeader("Accept", "application/json").
|
||||
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
|
||||
Get("/search_result")
|
||||
|
||||
|
||||
// Sample of using Request.SetQueryString method
|
||||
resp, err := client.R().
|
||||
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
|
||||
SetHeader("Accept", "application/json").
|
||||
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
|
||||
Get("/show_product")
|
||||
|
||||
|
||||
// If necessary, you can force response content type to tell Resty to parse a JSON response into your struct
|
||||
resp, err := client.R().
|
||||
SetResult(result).
|
||||
ForceContentType("application/json").
|
||||
Get("v2/alpine/manifests/latest")
|
||||
```
|
||||
|
||||
#### Various POST method combinations
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// POST JSON string
|
||||
// No need to set content type, if you have client level setting
|
||||
resp, err := client.R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(`{"username":"testuser", "password":"testpass"}`).
|
||||
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
|
||||
Post("https://myapp.com/login")
|
||||
|
||||
// POST []byte array
|
||||
// No need to set content type, if you have client level setting
|
||||
resp, err := client.R().
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
|
||||
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
|
||||
Post("https://myapp.com/login")
|
||||
|
||||
// POST Struct, default is JSON content type. No need to set one
|
||||
resp, err := client.R().
|
||||
SetBody(User{Username: "testuser", Password: "testpass"}).
|
||||
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
|
||||
SetError(&AuthError{}). // or SetError(AuthError{}).
|
||||
Post("https://myapp.com/login")
|
||||
|
||||
// POST Map, default is JSON content type. No need to set one
|
||||
resp, err := client.R().
|
||||
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
|
||||
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
|
||||
SetError(&AuthError{}). // or SetError(AuthError{}).
|
||||
Post("https://myapp.com/login")
|
||||
|
||||
// POST of raw bytes for file upload. For example: upload file to Dropbox
|
||||
fileBytes, _ := ioutil.ReadFile("/Users/jeeva/mydocument.pdf")
|
||||
|
||||
// See we are not setting content-type header, since go-resty automatically detects Content-Type for you
|
||||
resp, err := client.R().
|
||||
SetBody(fileBytes).
|
||||
SetContentLength(true). // Dropbox expects this value
|
||||
SetAuthToken("<your-auth-token>").
|
||||
SetError(&DropboxError{}). // or SetError(DropboxError{}).
|
||||
Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // for upload Dropbox supports PUT too
|
||||
|
||||
// Note: resty detects Content-Type for request body/payload if content type header is not set.
|
||||
// * For struct and map data type defaults to 'application/json'
|
||||
// * Fallback is plain text content type
|
||||
```
|
||||
|
||||
#### Sample PUT
|
||||
|
||||
You can use various combinations of `PUT` method call like demonstrated for `POST`.
|
||||
|
||||
```go
|
||||
// Note: This is one sample of PUT method usage, refer POST for more combination
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Request goes as JSON content type
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetBody(Article{
|
||||
Title: "go-resty",
|
||||
Content: "This is my article content, oh ya!",
|
||||
Author: "Jeevanandam M",
|
||||
Tags: []string{"article", "sample", "resty"},
|
||||
}).
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
SetError(&Error{}). // or SetError(Error{}).
|
||||
Put("https://myapp.com/article/1234")
|
||||
```
|
||||
|
||||
#### Sample PATCH
|
||||
|
||||
You can use various combinations of `PATCH` method call like demonstrated for `POST`.
|
||||
|
||||
```go
|
||||
// Note: This is one sample of PUT method usage, refer POST for more combination
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Request goes as JSON content type
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetBody(Article{
|
||||
Tags: []string{"new tag1", "new tag2"},
|
||||
}).
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
SetError(&Error{}). // or SetError(Error{}).
|
||||
Patch("https://myapp.com/articles/1234")
|
||||
```
|
||||
|
||||
#### Sample DELETE, HEAD, OPTIONS
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// DELETE a article
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
SetError(&Error{}). // or SetError(Error{}).
|
||||
Delete("https://myapp.com/articles/1234")
|
||||
|
||||
// DELETE a articles with payload/body as a JSON string
|
||||
// No need to set auth token, error, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
SetError(&Error{}). // or SetError(Error{}).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(`{article_ids: [1002, 1006, 1007, 87683, 45432] }`).
|
||||
Delete("https://myapp.com/articles")
|
||||
|
||||
// HEAD of resource
|
||||
// No need to set auth token, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
Head("https://myapp.com/videos/hi-res-video")
|
||||
|
||||
// OPTIONS of resource
|
||||
// No need to set auth token, if you have client level settings
|
||||
resp, err := client.R().
|
||||
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
|
||||
Options("https://myapp.com/servers/nyc-dc-01")
|
||||
```
|
||||
|
||||
#### Override JSON & XML Marshal/Unmarshal
|
||||
|
||||
User could register choice of JSON/XML library into resty or write your own. By default resty registers standard `encoding/json` and `encoding/xml` respectively.
|
||||
```go
|
||||
// Example of registering json-iterator
|
||||
import jsoniter "github.com/json-iterator/go"
|
||||
|
||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
client := resty.New()
|
||||
client.JSONMarshal = json.Marshal
|
||||
client.JSONUnmarshal = json.Unmarshal
|
||||
|
||||
// similarly user could do for XML too with -
|
||||
client.XMLMarshal
|
||||
client.XMLUnmarshal
|
||||
```
|
||||
|
||||
### Multipart File(s) upload
|
||||
|
||||
#### Using io.Reader
|
||||
|
||||
```go
|
||||
profileImgBytes, _ := ioutil.ReadFile("/Users/jeeva/test-img.png")
|
||||
notesBytes, _ := ioutil.ReadFile("/Users/jeeva/text-file.txt")
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
resp, err := client.R().
|
||||
SetFileReader("profile_img", "test-img.png", bytes.NewReader(profileImgBytes)).
|
||||
SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
|
||||
SetFormData(map[string]string{
|
||||
"first_name": "Jeevanandam",
|
||||
"last_name": "M",
|
||||
}).
|
||||
Post("http://myapp.com/upload")
|
||||
```
|
||||
|
||||
#### Using File directly from Path
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Single file scenario
|
||||
resp, err := client.R().
|
||||
SetFile("profile_img", "/Users/jeeva/test-img.png").
|
||||
Post("http://myapp.com/upload")
|
||||
|
||||
// Multiple files scenario
|
||||
resp, err := client.R().
|
||||
SetFiles(map[string]string{
|
||||
"profile_img": "/Users/jeeva/test-img.png",
|
||||
"notes": "/Users/jeeva/text-file.txt",
|
||||
}).
|
||||
Post("http://myapp.com/upload")
|
||||
|
||||
// Multipart of form fields and files
|
||||
resp, err := client.R().
|
||||
SetFiles(map[string]string{
|
||||
"profile_img": "/Users/jeeva/test-img.png",
|
||||
"notes": "/Users/jeeva/text-file.txt",
|
||||
}).
|
||||
SetFormData(map[string]string{
|
||||
"first_name": "Jeevanandam",
|
||||
"last_name": "M",
|
||||
"zip_code": "00001",
|
||||
"city": "my city",
|
||||
"access_token": "C6A79608-782F-4ED0-A11D-BD82FAD829CD",
|
||||
}).
|
||||
Post("http://myapp.com/profile")
|
||||
```
|
||||
|
||||
#### Sample Form submission
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// just mentioning about POST as an example with simple flow
|
||||
// User Login
|
||||
resp, err := client.R().
|
||||
SetFormData(map[string]string{
|
||||
"username": "jeeva",
|
||||
"password": "mypass",
|
||||
}).
|
||||
Post("http://myapp.com/login")
|
||||
|
||||
// Followed by profile update
|
||||
resp, err := client.R().
|
||||
SetFormData(map[string]string{
|
||||
"first_name": "Jeevanandam",
|
||||
"last_name": "M",
|
||||
"zip_code": "00001",
|
||||
"city": "new city update",
|
||||
}).
|
||||
Post("http://myapp.com/profile")
|
||||
|
||||
// Multi value form data
|
||||
criteria := url.Values{
|
||||
"search_criteria": []string{"book", "glass", "pencil"},
|
||||
}
|
||||
resp, err := client.R().
|
||||
SetFormDataFromValues(criteria).
|
||||
Post("http://myapp.com/search")
|
||||
```
|
||||
|
||||
#### Save HTTP Response into File
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Setting output directory path, If directory not exists then resty creates one!
|
||||
// This is optional one, if you're planning using absoule path in
|
||||
// `Request.SetOutput` and can used together.
|
||||
client.SetOutputDirectory("/Users/jeeva/Downloads")
|
||||
|
||||
// HTTP response gets saved into file, similar to curl -o flag
|
||||
_, err := client.R().
|
||||
SetOutput("plugin/ReplyWithHeader-v5.1-beta.zip").
|
||||
Get("http://bit.ly/1LouEKr")
|
||||
|
||||
// OR using absolute path
|
||||
// Note: output directory path is not used for absolute path
|
||||
_, err := client.R().
|
||||
SetOutput("/MyDownloads/plugin/ReplyWithHeader-v5.1-beta.zip").
|
||||
Get("http://bit.ly/1LouEKr")
|
||||
```
|
||||
|
||||
#### Request URL Path Params
|
||||
|
||||
Resty provides easy to use dynamic request URL path params. Params can be set at client and request level. Client level params value can be overridden at request level.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.R().SetPathParams(map[string]string{
|
||||
"userId": "sample@sample.com",
|
||||
"subAccountId": "100002",
|
||||
}).
|
||||
Get("/v1/users/{userId}/{subAccountId}/details")
|
||||
|
||||
// Result:
|
||||
// Composed URL - /v1/users/sample@sample.com/100002/details
|
||||
```
|
||||
|
||||
#### Request and Response Middleware
|
||||
|
||||
Resty provides middleware ability to manipulate for Request and Response. It is more flexible than callback approach.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Registering Request Middleware
|
||||
client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
|
||||
// Now you have access to Client and current Request object
|
||||
// manipulate it as per your need
|
||||
|
||||
return nil // if its success otherwise return error
|
||||
})
|
||||
|
||||
// Registering Response Middleware
|
||||
client.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
|
||||
// Now you have access to Client and current Response object
|
||||
// manipulate it as per your need
|
||||
|
||||
return nil // if its success otherwise return error
|
||||
})
|
||||
```
|
||||
|
||||
#### OnError Hooks
|
||||
|
||||
Resty provides OnError hooks that may be called because:
|
||||
|
||||
- The client failed to send the request due to connection timeout, TLS handshake failure, etc...
|
||||
- The request was retried the maximum amount of times, and still failed.
|
||||
|
||||
If there was a response from the server, the original error will be wrapped in `*resty.ResponseError` which contains the last response received.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.OnError(func(req *resty.Request, err error) {
|
||||
if v, ok := err.(*resty.ResponseError); ok {
|
||||
// v.Response contains the last response from the server
|
||||
// v.Err contains the original error
|
||||
}
|
||||
// Log the error, increment a metric, etc...
|
||||
})
|
||||
```
|
||||
|
||||
#### Redirect Policy
|
||||
|
||||
Resty provides few ready to use redirect policy(s) also it supports multiple policies together.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Assign Client Redirect Policy. Create one as per you need
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))
|
||||
|
||||
// Wanna multiple policies such as redirect count, domain name check, etc
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20),
|
||||
resty.DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
|
||||
```
|
||||
|
||||
##### Custom Redirect Policy
|
||||
|
||||
Implement [RedirectPolicy](redirect.go#L20) interface and register it with resty client. Have a look [redirect.go](redirect.go) for more information.
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Using raw func into resty.SetRedirectPolicy
|
||||
client.SetRedirectPolicy(resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
// Implement your logic here
|
||||
|
||||
// return nil for continue redirect otherwise return error to stop/prevent redirect
|
||||
return nil
|
||||
}))
|
||||
|
||||
//---------------------------------------------------
|
||||
|
||||
// Using struct create more flexible redirect policy
|
||||
type CustomRedirectPolicy struct {
|
||||
// variables goes here
|
||||
}
|
||||
|
||||
func (c *CustomRedirectPolicy) Apply(req *http.Request, via []*http.Request) error {
|
||||
// Implement your logic here
|
||||
|
||||
// return nil for continue redirect otherwise return error to stop/prevent redirect
|
||||
return nil
|
||||
}
|
||||
|
||||
// Registering in resty
|
||||
client.SetRedirectPolicy(CustomRedirectPolicy{/* initialize variables */})
|
||||
```
|
||||
|
||||
#### Custom Root Certificates and Client Certificates
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Custom Root certificates, just supply .pem file.
|
||||
// you can add one or more root certificates, its get appended
|
||||
client.SetRootCertificate("/path/to/root/pemFile1.pem")
|
||||
client.SetRootCertificate("/path/to/root/pemFile2.pem")
|
||||
// ... and so on!
|
||||
|
||||
// Adding Client Certificates, you add one or more certificates
|
||||
// Sample for creating certificate object
|
||||
// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
|
||||
cert1, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR client certificate: %s", err)
|
||||
}
|
||||
// ...
|
||||
|
||||
// You add one or more certificates
|
||||
client.SetCertificates(cert1, cert2, cert3)
|
||||
```
|
||||
|
||||
#### Custom Root Certificates and Client Certificates from string
|
||||
|
||||
```go
|
||||
// Custom Root certificates from string
|
||||
// You can pass you certificates throught env variables as strings
|
||||
// you can add one or more root certificates, its get appended
|
||||
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
|
||||
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
|
||||
// ... and so on!
|
||||
|
||||
// Adding Client Certificates, you add one or more certificates
|
||||
// Sample for creating certificate object
|
||||
// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
|
||||
cert1, err := tls.X509KeyPair([]byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"), []byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"))
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR client certificate: %s", err)
|
||||
}
|
||||
// ...
|
||||
|
||||
// You add one or more certificates
|
||||
client.SetCertificates(cert1, cert2, cert3)
|
||||
```
|
||||
|
||||
#### Proxy Settings - Client as well as at Request Level
|
||||
|
||||
Default `Go` supports Proxy via environment variable `HTTP_PROXY`. Resty provides support via `SetProxy` & `RemoveProxy`.
|
||||
Choose as per your need.
|
||||
|
||||
**Client Level Proxy** settings applied to all the request
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Setting a Proxy URL and Port
|
||||
client.SetProxy("http://proxyserver:8888")
|
||||
|
||||
// Want to remove proxy setting
|
||||
client.RemoveProxy()
|
||||
```
|
||||
|
||||
#### Retries
|
||||
|
||||
Resty uses [backoff](http://www.awsarchitectureblog.com/2015/03/backoff.html)
|
||||
to increase retry intervals after each attempt.
|
||||
|
||||
Usage example:
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Retries are configured per client
|
||||
client.
|
||||
// Set retry count to non zero to enable retries
|
||||
SetRetryCount(3).
|
||||
// You can override initial retry wait time.
|
||||
// Default is 100 milliseconds.
|
||||
SetRetryWaitTime(5 * time.Second).
|
||||
// MaxWaitTime can be overridden as well.
|
||||
// Default is 2 seconds.
|
||||
SetRetryMaxWaitTime(20 * time.Second).
|
||||
// SetRetryAfter sets callback to calculate wait time between retries.
|
||||
// Default (nil) implies exponential backoff with jitter
|
||||
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||
return 0, errors.New("quota exceeded")
|
||||
})
|
||||
```
|
||||
|
||||
Above setup will result in resty retrying requests returned non nil error up to
|
||||
3 times with delay increased after each attempt.
|
||||
|
||||
You can optionally provide client with [custom retry conditions](https://pkg.go.dev/github.com/go-resty/resty/v2#RetryConditionFunc):
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
client.AddRetryCondition(
|
||||
// RetryConditionFunc type is for retry condition function
|
||||
// input: non-nil Response OR request execution error
|
||||
func(r *resty.Response, err error) bool {
|
||||
return r.StatusCode() == http.StatusTooManyRequests
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
Above example will make resty retry requests ended with `429 Too Many Requests`
|
||||
status code.
|
||||
|
||||
Multiple retry conditions can be added.
|
||||
|
||||
It is also possible to use `resty.Backoff(...)` to get arbitrary retry scenarios
|
||||
implemented. [Reference](retry_test.go).
|
||||
|
||||
#### Allow GET request with Payload
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Allow GET request with Payload. This is disabled by default.
|
||||
client.SetAllowGetMethodPayload(true)
|
||||
```
|
||||
|
||||
#### Wanna Multiple Clients
|
||||
|
||||
```go
|
||||
// Here you go!
|
||||
// Client 1
|
||||
client1 := resty.New()
|
||||
client1.R().Get("http://httpbin.org")
|
||||
// ...
|
||||
|
||||
// Client 2
|
||||
client2 := resty.New()
|
||||
client2.R().Head("http://httpbin.org")
|
||||
// ...
|
||||
|
||||
// Bend it as per your need!!!
|
||||
```
|
||||
|
||||
#### Remaining Client Settings & its Options
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Unique settings at Client level
|
||||
//--------------------------------
|
||||
// Enable debug mode
|
||||
client.SetDebug(true)
|
||||
|
||||
// Assign Client TLSClientConfig
|
||||
// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
|
||||
client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })
|
||||
|
||||
// or One can disable security check (https)
|
||||
client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })
|
||||
|
||||
// Set client timeout as per your need
|
||||
client.SetTimeout(1 * time.Minute)
|
||||
|
||||
|
||||
// You can override all below settings and options at request level if you want to
|
||||
//--------------------------------------------------------------------------------
|
||||
// Host URL for all request. So you can use relative URL in the request
|
||||
client.SetHostURL("http://httpbin.org")
|
||||
|
||||
// Headers for all request
|
||||
client.SetHeader("Accept", "application/json")
|
||||
client.SetHeaders(map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "My custom User Agent String",
|
||||
})
|
||||
|
||||
// Cookies for all request
|
||||
client.SetCookie(&http.Cookie{
|
||||
Name:"go-resty",
|
||||
Value:"This is cookie value",
|
||||
Path: "/",
|
||||
Domain: "sample.com",
|
||||
MaxAge: 36000,
|
||||
HttpOnly: true,
|
||||
Secure: false,
|
||||
})
|
||||
client.SetCookies(cookies)
|
||||
|
||||
// URL query parameters for all request
|
||||
client.SetQueryParam("user_id", "00001")
|
||||
client.SetQueryParams(map[string]string{ // sample of those who use this manner
|
||||
"api_key": "api-key-here",
|
||||
"api_secert": "api-secert",
|
||||
})
|
||||
client.R().SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")
|
||||
|
||||
// Form data for all request. Typically used with POST and PUT
|
||||
client.SetFormData(map[string]string{
|
||||
"access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
|
||||
})
|
||||
|
||||
// Basic Auth for all request
|
||||
client.SetBasicAuth("myuser", "mypass")
|
||||
|
||||
// Bearer Auth Token for all request
|
||||
client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
|
||||
|
||||
// Enabling Content length value for all request
|
||||
client.SetContentLength(true)
|
||||
|
||||
// Registering global Error object structure for JSON/XML request
|
||||
client.SetError(&Error{}) // or resty.SetError(Error{})
|
||||
```
|
||||
|
||||
#### Unix Socket
|
||||
|
||||
```go
|
||||
unixSocket := "/var/run/my_socket.sock"
|
||||
|
||||
// Create a Go's http.Transport so we can set it in resty.
|
||||
transport := http.Transport{
|
||||
Dial: func(_, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", unixSocket)
|
||||
},
|
||||
}
|
||||
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Set the previous transport that we created, set the scheme of the communication to the
|
||||
// socket and set the unixSocket as the HostURL.
|
||||
client.SetTransport(&transport).SetScheme("http").SetHostURL(unixSocket)
|
||||
|
||||
// No need to write the host's URL on the request, just the path.
|
||||
client.R().Get("/index.html")
|
||||
```
|
||||
|
||||
#### Bazel Support
|
||||
|
||||
Resty can be built, tested and depended upon via [Bazel](https://bazel.build).
|
||||
For example, to run all tests:
|
||||
|
||||
```shell
|
||||
bazel test :resty_test
|
||||
```
|
||||
|
||||
#### Mocking http requests using [httpmock](https://github.com/jarcoal/httpmock) library
|
||||
|
||||
In order to mock the http requests when testing your application you
|
||||
could use the `httpmock` library.
|
||||
|
||||
When using the default resty client, you should pass the client to the library as follow:
|
||||
|
||||
```go
|
||||
// Create a Resty Client
|
||||
client := resty.New()
|
||||
|
||||
// Get the underlying HTTP Client and set it to Mock
|
||||
httpmock.ActivateNonDefault(client.GetClient())
|
||||
```
|
||||
|
||||
More detailed example of mocking resty http requests using ginko could be found [here](https://github.com/jarcoal/httpmock#ginkgo--resty-example).
|
||||
|
||||
## Versioning
|
||||
|
||||
Resty releases versions according to [Semantic Versioning](http://semver.org)
|
||||
|
||||
* Resty v2 does not use `gopkg.in` service for library versioning.
|
||||
* Resty fully adapted to `go mod` capabilities since `v1.10.0` release.
|
||||
* Resty v1 series was using `gopkg.in` to provide versioning. `gopkg.in/resty.vX` points to appropriate tagged versions; `X` denotes version series number and it's a stable release for production use. For e.g. `gopkg.in/resty.v0`.
|
||||
* Development takes place at the master branch. Although the code in master should always compile and test successfully, it might break API's. I aim to maintain backwards compatibility, but sometimes API's and behavior might be changed to fix a bug.
|
||||
|
||||
## Contribution
|
||||
|
||||
I would welcome your contribution! If you find any improvement or issue you want to fix, feel free to send a pull request, I like pull requests that include test cases for fix/enhancement. I have done my best to bring pretty good code coverage. Feel free to write tests.
|
||||
|
||||
BTW, I'd like to know what you think about `Resty`. Kindly open an issue or send me an email; it'd mean a lot to me.
|
||||
|
||||
## Creator
|
||||
|
||||
[Jeevanandam M.](https://github.com/jeevatkm) (jeeva@myjeeva.com)
|
||||
|
||||
## Core Team
|
||||
|
||||
Have a look on [Members](https://github.com/orgs/go-resty/people) page.
|
||||
|
||||
## Contributors
|
||||
|
||||
Have a look on [Contributors](https://github.com/go-resty/resty/graphs/contributors) page.
|
||||
|
||||
## License
|
||||
|
||||
Resty released under MIT license, refer [LICENSE](LICENSE) file.
|
||||
31
vendor/github.com/go-resty/resty/v2/WORKSPACE
generated
vendored
31
vendor/github.com/go-resty/resty/v2/WORKSPACE
generated
vendored
|
|
@ -1,31 +0,0 @@
|
|||
workspace(name = "resty")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "69de5c704a05ff37862f7e0f5534d4f479418afc21806c887db544a316f3cb6b",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "bazel_gazelle",
|
||||
sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(version = "1.16")
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies()
|
||||
1115
vendor/github.com/go-resty/resty/v2/client.go
generated
vendored
1115
vendor/github.com/go-resty/resty/v2/client.go
generated
vendored
File diff suppressed because it is too large
Load diff
543
vendor/github.com/go-resty/resty/v2/middleware.go
generated
vendored
543
vendor/github.com/go-resty/resty/v2/middleware.go
generated
vendored
|
|
@ -1,543 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const debugRequestLogKey = "__restyDebugRequestLog"
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request Middleware(s)
|
||||
//_______________________________________________________________________
|
||||
|
||||
func parseRequestURL(c *Client, r *Request) error {
|
||||
// GitHub #103 Path Params
|
||||
if len(r.PathParams) > 0 {
|
||||
for p, v := range r.PathParams {
|
||||
r.URL = strings.Replace(r.URL, "{"+p+"}", url.PathEscape(v), -1)
|
||||
}
|
||||
}
|
||||
if len(c.PathParams) > 0 {
|
||||
for p, v := range c.PathParams {
|
||||
r.URL = strings.Replace(r.URL, "{"+p+"}", url.PathEscape(v), -1)
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing request URL
|
||||
reqURL, err := url.Parse(r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If Request.URL is relative path then added c.HostURL into
|
||||
// the request URL otherwise Request.URL will be used as-is
|
||||
if !reqURL.IsAbs() {
|
||||
r.URL = reqURL.String()
|
||||
if len(r.URL) > 0 && r.URL[0] != '/' {
|
||||
r.URL = "/" + r.URL
|
||||
}
|
||||
|
||||
reqURL, err = url.Parse(c.HostURL + r.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// GH #407 && #318
|
||||
if reqURL.Scheme == "" && len(c.scheme) > 0 {
|
||||
reqURL.Scheme = c.scheme
|
||||
}
|
||||
|
||||
// Adding Query Param
|
||||
query := make(url.Values)
|
||||
for k, v := range c.QueryParam {
|
||||
for _, iv := range v {
|
||||
query.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.QueryParam {
|
||||
// remove query param from client level by key
|
||||
// since overrides happens for that key in the request
|
||||
query.Del(k)
|
||||
|
||||
for _, iv := range v {
|
||||
query.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #123 Preserve query string order partially.
|
||||
// Since not feasible in `SetQuery*` resty methods, because
|
||||
// standard package `url.Encode(...)` sorts the query params
|
||||
// alphabetically
|
||||
if len(query) > 0 {
|
||||
if IsStringEmpty(reqURL.RawQuery) {
|
||||
reqURL.RawQuery = query.Encode()
|
||||
} else {
|
||||
reqURL.RawQuery = reqURL.RawQuery + "&" + query.Encode()
|
||||
}
|
||||
}
|
||||
|
||||
r.URL = reqURL.String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestHeader(c *Client, r *Request) error {
|
||||
hdr := make(http.Header)
|
||||
for k := range c.Header {
|
||||
hdr[k] = append(hdr[k], c.Header[k]...)
|
||||
}
|
||||
|
||||
for k := range r.Header {
|
||||
hdr.Del(k)
|
||||
hdr[k] = append(hdr[k], r.Header[k]...)
|
||||
}
|
||||
|
||||
if IsStringEmpty(hdr.Get(hdrUserAgentKey)) {
|
||||
hdr.Set(hdrUserAgentKey, hdrUserAgentValue)
|
||||
}
|
||||
|
||||
ct := hdr.Get(hdrContentTypeKey)
|
||||
if IsStringEmpty(hdr.Get(hdrAcceptKey)) && !IsStringEmpty(ct) &&
|
||||
(IsJSONType(ct) || IsXMLType(ct)) {
|
||||
hdr.Set(hdrAcceptKey, hdr.Get(hdrContentTypeKey))
|
||||
}
|
||||
|
||||
r.Header = hdr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseRequestBody(c *Client, r *Request) (err error) {
|
||||
if isPayloadSupported(r.Method, c.AllowGetMethodPayload) {
|
||||
// Handling Multipart
|
||||
if r.isMultiPart && !(r.Method == MethodPatch) {
|
||||
if err = handleMultipart(c, r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
goto CL
|
||||
}
|
||||
|
||||
// Handling Form Data
|
||||
if len(c.FormData) > 0 || len(r.FormData) > 0 {
|
||||
handleFormData(c, r)
|
||||
|
||||
goto CL
|
||||
}
|
||||
|
||||
// Handling Request body
|
||||
if r.Body != nil {
|
||||
handleContentType(c, r)
|
||||
|
||||
if err = handleRequestBody(c, r); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CL:
|
||||
// by default resty won't set content length, you can if you want to :)
|
||||
if (c.setContentLength || r.setContentLength) && r.bodyBuf != nil {
|
||||
r.Header.Set(hdrContentLengthKey, fmt.Sprintf("%d", r.bodyBuf.Len()))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func createHTTPRequest(c *Client, r *Request) (err error) {
|
||||
if r.bodyBuf == nil {
|
||||
if reader, ok := r.Body.(io.Reader); ok {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, reader)
|
||||
} else if c.setContentLength || r.setContentLength {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, http.NoBody)
|
||||
} else {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, nil)
|
||||
}
|
||||
} else {
|
||||
r.RawRequest, err = http.NewRequest(r.Method, r.URL, r.bodyBuf)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Assign close connection option
|
||||
r.RawRequest.Close = c.closeConnection
|
||||
|
||||
// Add headers into http request
|
||||
r.RawRequest.Header = r.Header
|
||||
|
||||
// Add cookies from client instance into http request
|
||||
for _, cookie := range c.Cookies {
|
||||
r.RawRequest.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Add cookies from request instance into http request
|
||||
for _, cookie := range r.Cookies {
|
||||
r.RawRequest.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Enable trace
|
||||
if c.trace || r.trace {
|
||||
r.clientTrace = &clientTrace{}
|
||||
r.ctx = r.clientTrace.createContext(r.Context())
|
||||
}
|
||||
|
||||
// Use context if it was specified
|
||||
if r.ctx != nil {
|
||||
r.RawRequest = r.RawRequest.WithContext(r.ctx)
|
||||
}
|
||||
|
||||
bodyCopy, err := getBodyCopy(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// assign get body func for the underlying raw request instance
|
||||
r.RawRequest.GetBody = func() (io.ReadCloser, error) {
|
||||
if bodyCopy != nil {
|
||||
return ioutil.NopCloser(bytes.NewReader(bodyCopy.Bytes())), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func addCredentials(c *Client, r *Request) error {
|
||||
var isBasicAuth bool
|
||||
// Basic Auth
|
||||
if r.UserInfo != nil { // takes precedence
|
||||
r.RawRequest.SetBasicAuth(r.UserInfo.Username, r.UserInfo.Password)
|
||||
isBasicAuth = true
|
||||
} else if c.UserInfo != nil {
|
||||
r.RawRequest.SetBasicAuth(c.UserInfo.Username, c.UserInfo.Password)
|
||||
isBasicAuth = true
|
||||
}
|
||||
|
||||
if !c.DisableWarn {
|
||||
if isBasicAuth && !strings.HasPrefix(r.URL, "https") {
|
||||
c.log.Warnf("Using Basic Auth in HTTP mode is not secure, use HTTPS")
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Authorization Header Scheme
|
||||
var authScheme string
|
||||
if !IsStringEmpty(r.AuthScheme) {
|
||||
authScheme = r.AuthScheme
|
||||
} else if !IsStringEmpty(c.AuthScheme) {
|
||||
authScheme = c.AuthScheme
|
||||
} else {
|
||||
authScheme = "Bearer"
|
||||
}
|
||||
|
||||
// Build the Token Auth header
|
||||
if !IsStringEmpty(r.Token) { // takes precedence
|
||||
r.RawRequest.Header.Set(c.HeaderAuthorizationKey, authScheme+" "+r.Token)
|
||||
} else if !IsStringEmpty(c.Token) {
|
||||
r.RawRequest.Header.Set(c.HeaderAuthorizationKey, authScheme+" "+c.Token)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func requestLogger(c *Client, r *Request) error {
|
||||
if c.Debug {
|
||||
rr := r.RawRequest
|
||||
rl := &RequestLog{Header: copyHeaders(rr.Header), Body: r.fmtBodyString(c.debugBodySizeLimit)}
|
||||
if c.requestLog != nil {
|
||||
if err := c.requestLog(rl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// fmt.Sprintf("COOKIES:\n%s\n", composeCookies(c.GetClient().Jar, *rr.URL)) +
|
||||
|
||||
reqLog := "\n==============================================================================\n" +
|
||||
"~~~ REQUEST ~~~\n" +
|
||||
fmt.Sprintf("%s %s %s\n", r.Method, rr.URL.RequestURI(), rr.Proto) +
|
||||
fmt.Sprintf("HOST : %s\n", rr.URL.Host) +
|
||||
fmt.Sprintf("HEADERS:\n%s\n", composeHeaders(c, r, rl.Header)) +
|
||||
fmt.Sprintf("BODY :\n%v\n", rl.Body) +
|
||||
"------------------------------------------------------------------------------\n"
|
||||
|
||||
r.initValuesMap()
|
||||
r.values[debugRequestLogKey] = reqLog
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response Middleware(s)
|
||||
//_______________________________________________________________________
|
||||
|
||||
func responseLogger(c *Client, res *Response) error {
|
||||
if c.Debug {
|
||||
rl := &ResponseLog{Header: copyHeaders(res.Header()), Body: res.fmtBodyString(c.debugBodySizeLimit)}
|
||||
if c.responseLog != nil {
|
||||
if err := c.responseLog(rl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
debugLog := res.Request.values[debugRequestLogKey].(string)
|
||||
debugLog += "~~~ RESPONSE ~~~\n" +
|
||||
fmt.Sprintf("STATUS : %s\n", res.Status()) +
|
||||
fmt.Sprintf("PROTO : %s\n", res.RawResponse.Proto) +
|
||||
fmt.Sprintf("RECEIVED AT : %v\n", res.ReceivedAt().Format(time.RFC3339Nano)) +
|
||||
fmt.Sprintf("TIME DURATION: %v\n", res.Time()) +
|
||||
"HEADERS :\n" +
|
||||
composeHeaders(c, res.Request, rl.Header) + "\n"
|
||||
if res.Request.isSaveResponse {
|
||||
debugLog += "BODY :\n***** RESPONSE WRITTEN INTO FILE *****\n"
|
||||
} else {
|
||||
debugLog += fmt.Sprintf("BODY :\n%v\n", rl.Body)
|
||||
}
|
||||
debugLog += "==============================================================================\n"
|
||||
|
||||
c.log.Debugf("%s", debugLog)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseResponseBody(c *Client, res *Response) (err error) {
|
||||
if res.StatusCode() == http.StatusNoContent {
|
||||
return
|
||||
}
|
||||
// Handles only JSON or XML content type
|
||||
ct := firstNonEmpty(res.Request.forceContentType, res.Header().Get(hdrContentTypeKey), res.Request.fallbackContentType)
|
||||
if IsJSONType(ct) || IsXMLType(ct) {
|
||||
// HTTP status code > 199 and < 300, considered as Result
|
||||
if res.IsSuccess() {
|
||||
res.Request.Error = nil
|
||||
if res.Request.Result != nil {
|
||||
err = Unmarshalc(c, ct, res.body, res.Request.Result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP status code > 399, considered as Error
|
||||
if res.IsError() {
|
||||
// global error interface
|
||||
if res.Request.Error == nil && c.Error != nil {
|
||||
res.Request.Error = reflect.New(c.Error).Interface()
|
||||
}
|
||||
|
||||
if res.Request.Error != nil {
|
||||
err = Unmarshalc(c, ct, res.body, res.Request.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleMultipart(c *Client, r *Request) (err error) {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
w := multipart.NewWriter(r.bodyBuf)
|
||||
|
||||
for k, v := range c.FormData {
|
||||
for _, iv := range v {
|
||||
if err = w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.FormData {
|
||||
for _, iv := range v {
|
||||
if strings.HasPrefix(k, "@") { // file
|
||||
err = addFile(w, k[1:], iv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else { // form value
|
||||
if err = w.WriteField(k, iv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #21 - adding io.Reader support
|
||||
if len(r.multipartFiles) > 0 {
|
||||
for _, f := range r.multipartFiles {
|
||||
err = addFileReader(w, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub #130 adding multipart field support with content type
|
||||
if len(r.multipartFields) > 0 {
|
||||
for _, mf := range r.multipartFields {
|
||||
if err = addMultipartFormField(w, mf); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Header.Set(hdrContentTypeKey, w.FormDataContentType())
|
||||
err = w.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleFormData(c *Client, r *Request) {
|
||||
formData := url.Values{}
|
||||
|
||||
for k, v := range c.FormData {
|
||||
for _, iv := range v {
|
||||
formData.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range r.FormData {
|
||||
// remove form data field from client level by key
|
||||
// since overrides happens for that key in the request
|
||||
formData.Del(k)
|
||||
|
||||
for _, iv := range v {
|
||||
formData.Add(k, iv)
|
||||
}
|
||||
}
|
||||
|
||||
r.bodyBuf = bytes.NewBuffer([]byte(formData.Encode()))
|
||||
r.Header.Set(hdrContentTypeKey, formContentType)
|
||||
r.isFormData = true
|
||||
}
|
||||
|
||||
func handleContentType(c *Client, r *Request) {
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
if IsStringEmpty(contentType) {
|
||||
contentType = DetectContentType(r.Body)
|
||||
r.Header.Set(hdrContentTypeKey, contentType)
|
||||
}
|
||||
}
|
||||
|
||||
func handleRequestBody(c *Client, r *Request) (err error) {
|
||||
var bodyBytes []byte
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
kind := kindOf(r.Body)
|
||||
r.bodyBuf = nil
|
||||
|
||||
if reader, ok := r.Body.(io.Reader); ok {
|
||||
if c.setContentLength || r.setContentLength { // keep backward compatibility
|
||||
r.bodyBuf = acquireBuffer()
|
||||
_, err = r.bodyBuf.ReadFrom(reader)
|
||||
r.Body = nil
|
||||
} else {
|
||||
// Otherwise buffer less processing for `io.Reader`, sounds good.
|
||||
return
|
||||
}
|
||||
} else if b, ok := r.Body.([]byte); ok {
|
||||
bodyBytes = b
|
||||
} else if s, ok := r.Body.(string); ok {
|
||||
bodyBytes = []byte(s)
|
||||
} else if IsJSONType(contentType) &&
|
||||
(kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice) {
|
||||
r.bodyBuf, err = jsonMarshal(c, r, r.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else if IsXMLType(contentType) && (kind == reflect.Struct) {
|
||||
bodyBytes, err = c.XMLMarshal(r.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if bodyBytes == nil && r.bodyBuf == nil {
|
||||
err = errors.New("unsupported 'Body' type/value")
|
||||
}
|
||||
|
||||
// if any errors during body bytes handling, return it
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// []byte into Buffer
|
||||
if bodyBytes != nil && r.bodyBuf == nil {
|
||||
r.bodyBuf = acquireBuffer()
|
||||
_, _ = r.bodyBuf.Write(bodyBytes)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func saveResponseIntoFile(c *Client, res *Response) error {
|
||||
if res.Request.isSaveResponse {
|
||||
file := ""
|
||||
|
||||
if len(c.outputDirectory) > 0 && !filepath.IsAbs(res.Request.outputFile) {
|
||||
file += c.outputDirectory + string(filepath.Separator)
|
||||
}
|
||||
|
||||
file = filepath.Clean(file + res.Request.outputFile)
|
||||
if err := createDirectory(filepath.Dir(file)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outFile, err := os.Create(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(outFile)
|
||||
|
||||
// io.Copy reads maximum 32kb size, it is perfect for large file download too
|
||||
defer closeq(res.RawResponse.Body)
|
||||
|
||||
written, err := io.Copy(outFile, res.RawResponse.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.size = written
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBodyCopy(r *Request) (*bytes.Buffer, error) {
|
||||
// If r.bodyBuf present, return the copy
|
||||
if r.bodyBuf != nil {
|
||||
return bytes.NewBuffer(r.bodyBuf.Bytes()), nil
|
||||
}
|
||||
|
||||
// Maybe body is `io.Reader`.
|
||||
// Note: Resty user have to watchout for large body size of `io.Reader`
|
||||
if r.RawRequest.Body != nil {
|
||||
b, err := ioutil.ReadAll(r.RawRequest.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Restore the Body
|
||||
closeq(r.RawRequest.Body)
|
||||
r.RawRequest.Body = ioutil.NopCloser(bytes.NewBuffer(b))
|
||||
|
||||
// Return the Body bytes
|
||||
return bytes.NewBuffer(b), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
101
vendor/github.com/go-resty/resty/v2/redirect.go
generated
vendored
101
vendor/github.com/go-resty/resty/v2/redirect.go
generated
vendored
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// RedirectPolicy to regulate the redirects in the resty client.
|
||||
// Objects implementing the RedirectPolicy interface can be registered as
|
||||
//
|
||||
// Apply function should return nil to continue the redirect jounery, otherwise
|
||||
// return error to stop the redirect.
|
||||
RedirectPolicy interface {
|
||||
Apply(req *http.Request, via []*http.Request) error
|
||||
}
|
||||
|
||||
// The RedirectPolicyFunc type is an adapter to allow the use of ordinary functions as RedirectPolicy.
|
||||
// If f is a function with the appropriate signature, RedirectPolicyFunc(f) is a RedirectPolicy object that calls f.
|
||||
RedirectPolicyFunc func(*http.Request, []*http.Request) error
|
||||
)
|
||||
|
||||
// Apply calls f(req, via).
|
||||
func (f RedirectPolicyFunc) Apply(req *http.Request, via []*http.Request) error {
|
||||
return f(req, via)
|
||||
}
|
||||
|
||||
// NoRedirectPolicy is used to disable redirects in the HTTP client
|
||||
// resty.SetRedirectPolicy(NoRedirectPolicy())
|
||||
func NoRedirectPolicy() RedirectPolicy {
|
||||
return RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
return errors.New("auto redirect is disabled")
|
||||
})
|
||||
}
|
||||
|
||||
// FlexibleRedirectPolicy is convenient method to create No of redirect policy for HTTP client.
|
||||
// resty.SetRedirectPolicy(FlexibleRedirectPolicy(20))
|
||||
func FlexibleRedirectPolicy(noOfRedirect int) RedirectPolicy {
|
||||
return RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
if len(via) >= noOfRedirect {
|
||||
return fmt.Errorf("stopped after %d redirects", noOfRedirect)
|
||||
}
|
||||
checkHostAndAddHeaders(req, via[0])
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DomainCheckRedirectPolicy is convenient method to define domain name redirect rule in resty client.
|
||||
// Redirect is allowed for only mentioned host in the policy.
|
||||
// resty.SetRedirectPolicy(DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
|
||||
func DomainCheckRedirectPolicy(hostnames ...string) RedirectPolicy {
|
||||
hosts := make(map[string]bool)
|
||||
for _, h := range hostnames {
|
||||
hosts[strings.ToLower(h)] = true
|
||||
}
|
||||
|
||||
fn := RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
|
||||
if ok := hosts[getHostname(req.URL.Host)]; !ok {
|
||||
return errors.New("redirect is not allowed as per DomainCheckRedirectPolicy")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func getHostname(host string) (hostname string) {
|
||||
if strings.Index(host, ":") > 0 {
|
||||
host, _, _ = net.SplitHostPort(host)
|
||||
}
|
||||
hostname = strings.ToLower(host)
|
||||
return
|
||||
}
|
||||
|
||||
// By default Golang will not redirect request headers
|
||||
// after go throughing various discussion comments from thread
|
||||
// https://github.com/golang/go/issues/4800
|
||||
// Resty will add all the headers during a redirect for the same host
|
||||
func checkHostAndAddHeaders(cur *http.Request, pre *http.Request) {
|
||||
curHostname := getHostname(cur.URL.Host)
|
||||
preHostname := getHostname(pre.URL.Host)
|
||||
if strings.EqualFold(curHostname, preHostname) {
|
||||
for key, val := range pre.Header {
|
||||
cur.Header[key] = val
|
||||
}
|
||||
} else { // only library User-Agent header is added
|
||||
cur.Header.Set(hdrUserAgentKey, hdrUserAgentValue)
|
||||
}
|
||||
}
|
||||
896
vendor/github.com/go-resty/resty/v2/request.go
generated
vendored
896
vendor/github.com/go-resty/resty/v2/request.go
generated
vendored
|
|
@ -1,896 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request struct and methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Request struct is used to compose and fire individual request from
|
||||
// resty client. Request provides an options to override client level
|
||||
// settings and also an options for the request composition.
|
||||
type Request struct {
|
||||
URL string
|
||||
Method string
|
||||
Token string
|
||||
AuthScheme string
|
||||
QueryParam url.Values
|
||||
FormData url.Values
|
||||
PathParams map[string]string
|
||||
Header http.Header
|
||||
Time time.Time
|
||||
Body interface{}
|
||||
Result interface{}
|
||||
Error interface{}
|
||||
RawRequest *http.Request
|
||||
SRV *SRVRecord
|
||||
UserInfo *User
|
||||
Cookies []*http.Cookie
|
||||
|
||||
// Attempt is to represent the request attempt made during a Resty
|
||||
// request execution flow, including retry count.
|
||||
//
|
||||
// Since v2.4.0
|
||||
Attempt int
|
||||
|
||||
isMultiPart bool
|
||||
isFormData bool
|
||||
setContentLength bool
|
||||
isSaveResponse bool
|
||||
notParseResponse bool
|
||||
jsonEscapeHTML bool
|
||||
trace bool
|
||||
outputFile string
|
||||
fallbackContentType string
|
||||
forceContentType string
|
||||
ctx context.Context
|
||||
values map[string]interface{}
|
||||
client *Client
|
||||
bodyBuf *bytes.Buffer
|
||||
clientTrace *clientTrace
|
||||
multipartFiles []*File
|
||||
multipartFields []*MultipartField
|
||||
retryConditions []RetryConditionFunc
|
||||
}
|
||||
|
||||
// Context method returns the Context if its already set in request
|
||||
// otherwise it creates new one using `context.Background()`.
|
||||
func (r *Request) Context() context.Context {
|
||||
if r.ctx == nil {
|
||||
return context.Background()
|
||||
}
|
||||
return r.ctx
|
||||
}
|
||||
|
||||
// SetContext method sets the context.Context for current Request. It allows
|
||||
// to interrupt the request execution if ctx.Done() channel is closed.
|
||||
// See https://blog.golang.org/context article and the "context" package
|
||||
// documentation.
|
||||
func (r *Request) SetContext(ctx context.Context) *Request {
|
||||
r.ctx = ctx
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeader method is to set a single header field and its value in the current request.
|
||||
//
|
||||
// For Example: To set `Content-Type` and `Accept` as `application/json`.
|
||||
// client.R().
|
||||
// SetHeader("Content-Type", "application/json").
|
||||
// SetHeader("Accept", "application/json")
|
||||
//
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
func (r *Request) SetHeader(header, value string) *Request {
|
||||
r.Header.Set(header, value)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeaders method sets multiple headers field and its values at one go in the current request.
|
||||
//
|
||||
// For Example: To set `Content-Type` and `Accept` as `application/json`
|
||||
//
|
||||
// client.R().
|
||||
// SetHeaders(map[string]string{
|
||||
// "Content-Type": "application/json",
|
||||
// "Accept": "application/json",
|
||||
// })
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
func (r *Request) SetHeaders(headers map[string]string) *Request {
|
||||
for h, v := range headers {
|
||||
r.SetHeader(h, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeaderMultiValues sets multiple headers fields and its values is list of strings at one go in the current request.
|
||||
//
|
||||
// For Example: To set `Accept` as `text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8`
|
||||
//
|
||||
// client.R().
|
||||
// SetHeaderMultiValues(map[string][]string{
|
||||
// "Accept": []string{"text/html", "application/xhtml+xml", "application/xml;q=0.9", "image/webp", "*/*;q=0.8"},
|
||||
// })
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
func (r *Request) SetHeaderMultiValues(headers map[string][]string) *Request {
|
||||
for key, values := range headers {
|
||||
r.SetHeader(key, strings.Join(values, ", "))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeaderVerbatim method is to set a single header field and its value verbatim in the current request.
|
||||
//
|
||||
// For Example: To set `all_lowercase` and `UPPERCASE` as `available`.
|
||||
// client.R().
|
||||
// SetHeaderVerbatim("all_lowercase", "available").
|
||||
// SetHeaderVerbatim("UPPERCASE", "available")
|
||||
//
|
||||
// Also you can override header value, which was set at client instance level.
|
||||
//
|
||||
// Since v2.6.0
|
||||
func (r *Request) SetHeaderVerbatim(header, value string) *Request {
|
||||
r.Header[header] = []string{value}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryParam method sets single parameter and its value in the current request.
|
||||
// It will be formed as query string for the request.
|
||||
//
|
||||
// For Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.
|
||||
// client.R().
|
||||
// SetQueryParam("search", "kitchen papers").
|
||||
// SetQueryParam("size", "large")
|
||||
// Also you can override query params value, which was set at client instance level.
|
||||
func (r *Request) SetQueryParam(param, value string) *Request {
|
||||
r.QueryParam.Set(param, value)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryParams method sets multiple parameters and its values at one go in the current request.
|
||||
// It will be formed as query string for the request.
|
||||
//
|
||||
// For Example: `search=kitchen%20papers&size=large` in the URL after `?` mark.
|
||||
// client.R().
|
||||
// SetQueryParams(map[string]string{
|
||||
// "search": "kitchen papers",
|
||||
// "size": "large",
|
||||
// })
|
||||
// Also you can override query params value, which was set at client instance level.
|
||||
func (r *Request) SetQueryParams(params map[string]string) *Request {
|
||||
for p, v := range params {
|
||||
r.SetQueryParam(p, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryParamsFromValues method appends multiple parameters with multi-value
|
||||
// (`url.Values`) at one go in the current request. It will be formed as
|
||||
// query string for the request.
|
||||
//
|
||||
// For Example: `status=pending&status=approved&status=open` in the URL after `?` mark.
|
||||
// client.R().
|
||||
// SetQueryParamsFromValues(url.Values{
|
||||
// "status": []string{"pending", "approved", "open"},
|
||||
// })
|
||||
// Also you can override query params value, which was set at client instance level.
|
||||
func (r *Request) SetQueryParamsFromValues(params url.Values) *Request {
|
||||
for p, v := range params {
|
||||
for _, pv := range v {
|
||||
r.QueryParam.Add(p, pv)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetQueryString method provides ability to use string as an input to set URL query string for the request.
|
||||
//
|
||||
// Using String as an input
|
||||
// client.R().
|
||||
// SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")
|
||||
func (r *Request) SetQueryString(query string) *Request {
|
||||
params, err := url.ParseQuery(strings.TrimSpace(query))
|
||||
if err == nil {
|
||||
for p, v := range params {
|
||||
for _, pv := range v {
|
||||
r.QueryParam.Add(p, pv)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.client.log.Errorf("%v", err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFormData method sets Form parameters and their values in the current request.
|
||||
// It's applicable only HTTP method `POST` and `PUT` and requests content type would be set as
|
||||
// `application/x-www-form-urlencoded`.
|
||||
// client.R().
|
||||
// SetFormData(map[string]string{
|
||||
// "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
|
||||
// "user_id": "3455454545",
|
||||
// })
|
||||
// Also you can override form data value, which was set at client instance level.
|
||||
func (r *Request) SetFormData(data map[string]string) *Request {
|
||||
for k, v := range data {
|
||||
r.FormData.Set(k, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFormDataFromValues method appends multiple form parameters with multi-value
|
||||
// (`url.Values`) at one go in the current request.
|
||||
// client.R().
|
||||
// SetFormDataFromValues(url.Values{
|
||||
// "search_criteria": []string{"book", "glass", "pencil"},
|
||||
// })
|
||||
// Also you can override form data value, which was set at client instance level.
|
||||
func (r *Request) SetFormDataFromValues(data url.Values) *Request {
|
||||
for k, v := range data {
|
||||
for _, kv := range v {
|
||||
r.FormData.Add(k, kv)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBody method sets the request body for the request. It supports various realtime needs as easy.
|
||||
// We can say its quite handy or powerful. Supported request body data types is `string`,
|
||||
// `[]byte`, `struct`, `map`, `slice` and `io.Reader`. Body value can be pointer or non-pointer.
|
||||
// Automatic marshalling for JSON and XML content type, if it is `struct`, `map`, or `slice`.
|
||||
//
|
||||
// Note: `io.Reader` is processed as bufferless mode while sending request.
|
||||
//
|
||||
// For Example: Struct as a body input, based on content type, it will be marshalled.
|
||||
// client.R().
|
||||
// SetBody(User{
|
||||
// Username: "jeeva@myjeeva.com",
|
||||
// Password: "welcome2resty",
|
||||
// })
|
||||
//
|
||||
// Map as a body input, based on content type, it will be marshalled.
|
||||
// client.R().
|
||||
// SetBody(map[string]interface{}{
|
||||
// "username": "jeeva@myjeeva.com",
|
||||
// "password": "welcome2resty",
|
||||
// "address": &Address{
|
||||
// Address1: "1111 This is my street",
|
||||
// Address2: "Apt 201",
|
||||
// City: "My City",
|
||||
// State: "My State",
|
||||
// ZipCode: 00000,
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// String as a body input. Suitable for any need as a string input.
|
||||
// client.R().
|
||||
// SetBody(`{
|
||||
// "username": "jeeva@getrightcare.com",
|
||||
// "password": "admin"
|
||||
// }`)
|
||||
//
|
||||
// []byte as a body input. Suitable for raw request such as file upload, serialize & deserialize, etc.
|
||||
// client.R().
|
||||
// SetBody([]byte("This is my raw request, sent as-is"))
|
||||
func (r *Request) SetBody(body interface{}) *Request {
|
||||
r.Body = body
|
||||
return r
|
||||
}
|
||||
|
||||
// SetResult method is to register the response `Result` object for automatic unmarshalling for the request,
|
||||
// if response status code is between 200 and 299 and content type either JSON or XML.
|
||||
//
|
||||
// Note: Result object can be pointer or non-pointer.
|
||||
// client.R().SetResult(&AuthToken{})
|
||||
// // OR
|
||||
// client.R().SetResult(AuthToken{})
|
||||
//
|
||||
// Accessing a result value from response instance.
|
||||
// response.Result().(*AuthToken)
|
||||
func (r *Request) SetResult(res interface{}) *Request {
|
||||
r.Result = getPointer(res)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetError method is to register the request `Error` object for automatic unmarshalling for the request,
|
||||
// if response status code is greater than 399 and content type either JSON or XML.
|
||||
//
|
||||
// Note: Error object can be pointer or non-pointer.
|
||||
// client.R().SetError(&AuthError{})
|
||||
// // OR
|
||||
// client.R().SetError(AuthError{})
|
||||
//
|
||||
// Accessing a error value from response instance.
|
||||
// response.Error().(*AuthError)
|
||||
func (r *Request) SetError(err interface{}) *Request {
|
||||
r.Error = getPointer(err)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFile method is to set single file field name and its path for multipart upload.
|
||||
// client.R().
|
||||
// SetFile("my_file", "/Users/jeeva/Gas Bill - Sep.pdf")
|
||||
func (r *Request) SetFile(param, filePath string) *Request {
|
||||
r.isMultiPart = true
|
||||
r.FormData.Set("@"+param, filePath)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFiles method is to set multiple file field name and its path for multipart upload.
|
||||
// client.R().
|
||||
// SetFiles(map[string]string{
|
||||
// "my_file1": "/Users/jeeva/Gas Bill - Sep.pdf",
|
||||
// "my_file2": "/Users/jeeva/Electricity Bill - Sep.pdf",
|
||||
// "my_file3": "/Users/jeeva/Water Bill - Sep.pdf",
|
||||
// })
|
||||
func (r *Request) SetFiles(files map[string]string) *Request {
|
||||
r.isMultiPart = true
|
||||
for f, fp := range files {
|
||||
r.FormData.Set("@"+f, fp)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetFileReader method is to set single file using io.Reader for multipart upload.
|
||||
// client.R().
|
||||
// SetFileReader("profile_img", "my-profile-img.png", bytes.NewReader(profileImgBytes)).
|
||||
// SetFileReader("notes", "user-notes.txt", bytes.NewReader(notesBytes))
|
||||
func (r *Request) SetFileReader(param, fileName string, reader io.Reader) *Request {
|
||||
r.isMultiPart = true
|
||||
r.multipartFiles = append(r.multipartFiles, &File{
|
||||
Name: fileName,
|
||||
ParamName: param,
|
||||
Reader: reader,
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultipartFormData method allows simple form data to be attached to the request as `multipart:form-data`
|
||||
func (r *Request) SetMultipartFormData(data map[string]string) *Request {
|
||||
for k, v := range data {
|
||||
r = r.SetMultipartField(k, "", "", strings.NewReader(v))
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultipartField method is to set custom data using io.Reader for multipart upload.
|
||||
func (r *Request) SetMultipartField(param, fileName, contentType string, reader io.Reader) *Request {
|
||||
r.isMultiPart = true
|
||||
r.multipartFields = append(r.multipartFields, &MultipartField{
|
||||
Param: param,
|
||||
FileName: fileName,
|
||||
ContentType: contentType,
|
||||
Reader: reader,
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
// SetMultipartFields method is to set multiple data fields using io.Reader for multipart upload.
|
||||
//
|
||||
// For Example:
|
||||
// client.R().SetMultipartFields(
|
||||
// &resty.MultipartField{
|
||||
// Param: "uploadManifest1",
|
||||
// FileName: "upload-file-1.json",
|
||||
// ContentType: "application/json",
|
||||
// Reader: strings.NewReader(`{"input": {"name": "Uploaded document 1", "_filename" : ["file1.txt"]}}`),
|
||||
// },
|
||||
// &resty.MultipartField{
|
||||
// Param: "uploadManifest2",
|
||||
// FileName: "upload-file-2.json",
|
||||
// ContentType: "application/json",
|
||||
// Reader: strings.NewReader(`{"input": {"name": "Uploaded document 2", "_filename" : ["file2.txt"]}}`),
|
||||
// })
|
||||
//
|
||||
// If you have slice already, then simply call-
|
||||
// client.R().SetMultipartFields(fields...)
|
||||
func (r *Request) SetMultipartFields(fields ...*MultipartField) *Request {
|
||||
r.isMultiPart = true
|
||||
r.multipartFields = append(r.multipartFields, fields...)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetContentLength method sets the HTTP header `Content-Length` value for current request.
|
||||
// By default Resty won't set `Content-Length`. Also you have an option to enable for every
|
||||
// request.
|
||||
//
|
||||
// See `Client.SetContentLength`
|
||||
// client.R().SetContentLength(true)
|
||||
func (r *Request) SetContentLength(l bool) *Request {
|
||||
r.setContentLength = l
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBasicAuth method sets the basic authentication header in the current HTTP request.
|
||||
//
|
||||
// For Example:
|
||||
// Authorization: Basic <base64-encoded-value>
|
||||
//
|
||||
// To set the header for username "go-resty" and password "welcome"
|
||||
// client.R().SetBasicAuth("go-resty", "welcome")
|
||||
//
|
||||
// This method overrides the credentials set by method `Client.SetBasicAuth`.
|
||||
func (r *Request) SetBasicAuth(username, password string) *Request {
|
||||
r.UserInfo = &User{Username: username, Password: password}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetAuthToken method sets the auth token header(Default Scheme: Bearer) in the current HTTP request. Header example:
|
||||
// Authorization: Bearer <auth-token-value-comes-here>
|
||||
//
|
||||
// For Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
|
||||
//
|
||||
// client.R().SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
|
||||
//
|
||||
// This method overrides the Auth token set by method `Client.SetAuthToken`.
|
||||
func (r *Request) SetAuthToken(token string) *Request {
|
||||
r.Token = token
|
||||
return r
|
||||
}
|
||||
|
||||
// SetAuthScheme method sets the auth token scheme type in the HTTP request. For Example:
|
||||
// Authorization: <auth-scheme-value-set-here> <auth-token-value>
|
||||
//
|
||||
// For Example: To set the scheme to use OAuth
|
||||
//
|
||||
// client.R().SetAuthScheme("OAuth")
|
||||
//
|
||||
// This auth header scheme gets added to all the request rasied from this client instance.
|
||||
// Also it can be overridden or set one at the request level is supported.
|
||||
//
|
||||
// Information about Auth schemes can be found in RFC7235 which is linked to below along with the page containing
|
||||
// the currently defined official authentication schemes:
|
||||
// https://tools.ietf.org/html/rfc7235
|
||||
// https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml#authschemes
|
||||
//
|
||||
// This method overrides the Authorization scheme set by method `Client.SetAuthScheme`.
|
||||
func (r *Request) SetAuthScheme(scheme string) *Request {
|
||||
r.AuthScheme = scheme
|
||||
return r
|
||||
}
|
||||
|
||||
// SetOutput method sets the output file for current HTTP request. Current HTTP response will be
|
||||
// saved into given file. It is similar to `curl -o` flag. Absolute path or relative path can be used.
|
||||
// If is it relative path then output file goes under the output directory, as mentioned
|
||||
// in the `Client.SetOutputDirectory`.
|
||||
// client.R().
|
||||
// SetOutput("/Users/jeeva/Downloads/ReplyWithHeader-v5.1-beta.zip").
|
||||
// Get("http://bit.ly/1LouEKr")
|
||||
//
|
||||
// Note: In this scenario `Response.Body` might be nil.
|
||||
func (r *Request) SetOutput(file string) *Request {
|
||||
r.outputFile = file
|
||||
r.isSaveResponse = true
|
||||
return r
|
||||
}
|
||||
|
||||
// SetSRV method sets the details to query the service SRV record and execute the
|
||||
// request.
|
||||
// client.R().
|
||||
// SetSRV(SRVRecord{"web", "testservice.com"}).
|
||||
// Get("/get")
|
||||
func (r *Request) SetSRV(srv *SRVRecord) *Request {
|
||||
r.SRV = srv
|
||||
return r
|
||||
}
|
||||
|
||||
// SetDoNotParseResponse method instructs `Resty` not to parse the response body automatically.
|
||||
// Resty exposes the raw response body as `io.ReadCloser`. Also do not forget to close the body,
|
||||
// otherwise you might get into connection leaks, no connection reuse.
|
||||
//
|
||||
// Note: Response middlewares are not applicable, if you use this option. Basically you have
|
||||
// taken over the control of response parsing from `Resty`.
|
||||
func (r *Request) SetDoNotParseResponse(parse bool) *Request {
|
||||
r.notParseResponse = parse
|
||||
return r
|
||||
}
|
||||
|
||||
// SetPathParam method sets single URL path key-value pair in the
|
||||
// Resty current request instance.
|
||||
// client.R().SetPathParam("userId", "sample@sample.com")
|
||||
//
|
||||
// Result:
|
||||
// URL - /v1/users/{userId}/details
|
||||
// Composed URL - /v1/users/sample@sample.com/details
|
||||
// It replaces the value of the key while composing the request URL. Also you can
|
||||
// override Path Params value, which was set at client instance level.
|
||||
func (r *Request) SetPathParam(param, value string) *Request {
|
||||
r.PathParams[param] = value
|
||||
return r
|
||||
}
|
||||
|
||||
// SetPathParams method sets multiple URL path key-value pairs at one go in the
|
||||
// Resty current request instance.
|
||||
// client.R().SetPathParams(map[string]string{
|
||||
// "userId": "sample@sample.com",
|
||||
// "subAccountId": "100002",
|
||||
// })
|
||||
//
|
||||
// Result:
|
||||
// URL - /v1/users/{userId}/{subAccountId}/details
|
||||
// Composed URL - /v1/users/sample@sample.com/100002/details
|
||||
// It replaces the value of the key while composing request URL. Also you can
|
||||
// override Path Params value, which was set at client instance level.
|
||||
func (r *Request) SetPathParams(params map[string]string) *Request {
|
||||
for p, v := range params {
|
||||
r.SetPathParam(p, v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ExpectContentType method allows to provide fallback `Content-Type` for automatic unmarshalling
|
||||
// when `Content-Type` response header is unavailable.
|
||||
func (r *Request) ExpectContentType(contentType string) *Request {
|
||||
r.fallbackContentType = contentType
|
||||
return r
|
||||
}
|
||||
|
||||
// ForceContentType method provides a strong sense of response `Content-Type` for automatic unmarshalling.
|
||||
// Resty gives this a higher priority than the `Content-Type` response header. This means that if both
|
||||
// `Request.ForceContentType` is set and the response `Content-Type` is available, `ForceContentType` will win.
|
||||
func (r *Request) ForceContentType(contentType string) *Request {
|
||||
r.forceContentType = contentType
|
||||
return r
|
||||
}
|
||||
|
||||
// SetJSONEscapeHTML method is to enable/disable the HTML escape on JSON marshal.
|
||||
//
|
||||
// Note: This option only applicable to standard JSON Marshaller.
|
||||
func (r *Request) SetJSONEscapeHTML(b bool) *Request {
|
||||
r.jsonEscapeHTML = b
|
||||
return r
|
||||
}
|
||||
|
||||
// SetCookie method appends a single cookie in the current request instance.
|
||||
// client.R().SetCookie(&http.Cookie{
|
||||
// Name:"go-resty",
|
||||
// Value:"This is cookie value",
|
||||
// })
|
||||
//
|
||||
// Note: Method appends the Cookie value into existing Cookie if already existing.
|
||||
//
|
||||
// Since v2.1.0
|
||||
func (r *Request) SetCookie(hc *http.Cookie) *Request {
|
||||
r.Cookies = append(r.Cookies, hc)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetCookies method sets an array of cookies in the current request instance.
|
||||
// cookies := []*http.Cookie{
|
||||
// &http.Cookie{
|
||||
// Name:"go-resty-1",
|
||||
// Value:"This is cookie 1 value",
|
||||
// },
|
||||
// &http.Cookie{
|
||||
// Name:"go-resty-2",
|
||||
// Value:"This is cookie 2 value",
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // Setting a cookies into resty's current request
|
||||
// client.R().SetCookies(cookies)
|
||||
//
|
||||
// Note: Method appends the Cookie value into existing Cookie if already existing.
|
||||
//
|
||||
// Since v2.1.0
|
||||
func (r *Request) SetCookies(rs []*http.Cookie) *Request {
|
||||
r.Cookies = append(r.Cookies, rs...)
|
||||
return r
|
||||
}
|
||||
|
||||
// AddRetryCondition method adds a retry condition function to the request's
|
||||
// array of functions that are checked to determine if the request is retried.
|
||||
// The request will retry if any of the functions return true and error is nil.
|
||||
//
|
||||
// Note: These retry conditions are checked before all retry conditions of the client.
|
||||
//
|
||||
// Since v2.7.0
|
||||
func (r *Request) AddRetryCondition(condition RetryConditionFunc) *Request {
|
||||
r.retryConditions = append(r.retryConditions, condition)
|
||||
return r
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// HTTP request tracing
|
||||
//_______________________________________________________________________
|
||||
|
||||
// EnableTrace method enables trace for the current request
|
||||
// using `httptrace.ClientTrace` and provides insights.
|
||||
//
|
||||
// client := resty.New()
|
||||
//
|
||||
// resp, err := client.R().EnableTrace().Get("https://httpbin.org/get")
|
||||
// fmt.Println("Error:", err)
|
||||
// fmt.Println("Trace Info:", resp.Request.TraceInfo())
|
||||
//
|
||||
// See `Client.EnableTrace` available too to get trace info for all requests.
|
||||
//
|
||||
// Since v2.0.0
|
||||
func (r *Request) EnableTrace() *Request {
|
||||
r.trace = true
|
||||
return r
|
||||
}
|
||||
|
||||
// TraceInfo method returns the trace info for the request.
|
||||
// If either the Client or Request EnableTrace function has not been called
|
||||
// prior to the request being made, an empty TraceInfo object will be returned.
|
||||
//
|
||||
// Since v2.0.0
|
||||
func (r *Request) TraceInfo() TraceInfo {
|
||||
ct := r.clientTrace
|
||||
|
||||
if ct == nil {
|
||||
return TraceInfo{}
|
||||
}
|
||||
|
||||
ti := TraceInfo{
|
||||
DNSLookup: ct.dnsDone.Sub(ct.dnsStart),
|
||||
TLSHandshake: ct.tlsHandshakeDone.Sub(ct.tlsHandshakeStart),
|
||||
ServerTime: ct.gotFirstResponseByte.Sub(ct.gotConn),
|
||||
IsConnReused: ct.gotConnInfo.Reused,
|
||||
IsConnWasIdle: ct.gotConnInfo.WasIdle,
|
||||
ConnIdleTime: ct.gotConnInfo.IdleTime,
|
||||
RequestAttempt: r.Attempt,
|
||||
}
|
||||
|
||||
// Calculate the total time accordingly,
|
||||
// when connection is reused
|
||||
if ct.gotConnInfo.Reused {
|
||||
ti.TotalTime = ct.endTime.Sub(ct.getConn)
|
||||
} else {
|
||||
ti.TotalTime = ct.endTime.Sub(ct.dnsStart)
|
||||
}
|
||||
|
||||
// Only calculate on successful connections
|
||||
if !ct.connectDone.IsZero() {
|
||||
ti.TCPConnTime = ct.connectDone.Sub(ct.dnsDone)
|
||||
}
|
||||
|
||||
// Only calculate on successful connections
|
||||
if !ct.gotConn.IsZero() {
|
||||
ti.ConnTime = ct.gotConn.Sub(ct.getConn)
|
||||
}
|
||||
|
||||
// Only calculate on successful connections
|
||||
if !ct.gotFirstResponseByte.IsZero() {
|
||||
ti.ResponseTime = ct.endTime.Sub(ct.gotFirstResponseByte)
|
||||
}
|
||||
|
||||
// Capture remote address info when connection is non-nil
|
||||
if ct.gotConnInfo.Conn != nil {
|
||||
ti.RemoteAddr = ct.gotConnInfo.Conn.RemoteAddr()
|
||||
}
|
||||
|
||||
return ti
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// HTTP verb method starts here
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Get method does GET HTTP request. It's defined in section 4.3.1 of RFC7231.
|
||||
func (r *Request) Get(url string) (*Response, error) {
|
||||
return r.Execute(MethodGet, url)
|
||||
}
|
||||
|
||||
// Head method does HEAD HTTP request. It's defined in section 4.3.2 of RFC7231.
|
||||
func (r *Request) Head(url string) (*Response, error) {
|
||||
return r.Execute(MethodHead, url)
|
||||
}
|
||||
|
||||
// Post method does POST HTTP request. It's defined in section 4.3.3 of RFC7231.
|
||||
func (r *Request) Post(url string) (*Response, error) {
|
||||
return r.Execute(MethodPost, url)
|
||||
}
|
||||
|
||||
// Put method does PUT HTTP request. It's defined in section 4.3.4 of RFC7231.
|
||||
func (r *Request) Put(url string) (*Response, error) {
|
||||
return r.Execute(MethodPut, url)
|
||||
}
|
||||
|
||||
// Delete method does DELETE HTTP request. It's defined in section 4.3.5 of RFC7231.
|
||||
func (r *Request) Delete(url string) (*Response, error) {
|
||||
return r.Execute(MethodDelete, url)
|
||||
}
|
||||
|
||||
// Options method does OPTIONS HTTP request. It's defined in section 4.3.7 of RFC7231.
|
||||
func (r *Request) Options(url string) (*Response, error) {
|
||||
return r.Execute(MethodOptions, url)
|
||||
}
|
||||
|
||||
// Patch method does PATCH HTTP request. It's defined in section 2 of RFC5789.
|
||||
func (r *Request) Patch(url string) (*Response, error) {
|
||||
return r.Execute(MethodPatch, url)
|
||||
}
|
||||
|
||||
// Send method performs the HTTP request using the method and URL already defined
|
||||
// for current `Request`.
|
||||
// req := client.R()
|
||||
// req.Method = resty.GET
|
||||
// req.URL = "http://httpbin.org/get"
|
||||
// resp, err := client.R().Send()
|
||||
func (r *Request) Send() (*Response, error) {
|
||||
return r.Execute(r.Method, r.URL)
|
||||
}
|
||||
|
||||
// Execute method performs the HTTP request with given HTTP method and URL
|
||||
// for current `Request`.
|
||||
// resp, err := client.R().Execute(resty.GET, "http://httpbin.org/get")
|
||||
func (r *Request) Execute(method, url string) (*Response, error) {
|
||||
var addrs []*net.SRV
|
||||
var resp *Response
|
||||
var err error
|
||||
|
||||
if r.isMultiPart && !(method == MethodPost || method == MethodPut || method == MethodPatch) {
|
||||
// No OnError hook here since this is a request validation error
|
||||
return nil, fmt.Errorf("multipart content is not allowed in HTTP verb [%v]", method)
|
||||
}
|
||||
|
||||
if r.SRV != nil {
|
||||
_, addrs, err = net.LookupSRV(r.SRV.Service, "tcp", r.SRV.Domain)
|
||||
if err != nil {
|
||||
r.client.onErrorHooks(r, nil, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
r.Method = method
|
||||
r.URL = r.selectAddr(addrs, url, 0)
|
||||
|
||||
if r.client.RetryCount == 0 {
|
||||
r.Attempt = 1
|
||||
resp, err = r.client.execute(r)
|
||||
r.client.onErrorHooks(r, resp, unwrapNoRetryErr(err))
|
||||
return resp, unwrapNoRetryErr(err)
|
||||
}
|
||||
|
||||
err = Backoff(
|
||||
func() (*Response, error) {
|
||||
r.Attempt++
|
||||
|
||||
r.URL = r.selectAddr(addrs, url, r.Attempt)
|
||||
|
||||
resp, err = r.client.execute(r)
|
||||
if err != nil {
|
||||
r.client.log.Errorf("%v, Attempt %v", err, r.Attempt)
|
||||
}
|
||||
|
||||
return resp, err
|
||||
},
|
||||
Retries(r.client.RetryCount),
|
||||
WaitTime(r.client.RetryWaitTime),
|
||||
MaxWaitTime(r.client.RetryMaxWaitTime),
|
||||
RetryConditions(append(r.retryConditions, r.client.RetryConditions...)),
|
||||
RetryHooks(r.client.RetryHooks),
|
||||
)
|
||||
|
||||
r.client.onErrorHooks(r, resp, unwrapNoRetryErr(err))
|
||||
|
||||
return resp, unwrapNoRetryErr(err)
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// SRVRecord struct
|
||||
//_______________________________________________________________________
|
||||
|
||||
// SRVRecord struct holds the data to query the SRV record for the
|
||||
// following service.
|
||||
type SRVRecord struct {
|
||||
Service string
|
||||
Domain string
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Request Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func (r *Request) fmtBodyString(sl int64) (body string) {
|
||||
body = "***** NO CONTENT *****"
|
||||
if !isPayloadSupported(r.Method, r.client.AllowGetMethodPayload) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := r.Body.(io.Reader); ok {
|
||||
body = "***** BODY IS io.Reader *****"
|
||||
return
|
||||
}
|
||||
|
||||
// multipart or form-data
|
||||
if r.isMultiPart || r.isFormData {
|
||||
bodySize := int64(r.bodyBuf.Len())
|
||||
if bodySize > sl {
|
||||
body = fmt.Sprintf("***** REQUEST TOO LARGE (size - %d) *****", bodySize)
|
||||
return
|
||||
}
|
||||
body = r.bodyBuf.String()
|
||||
return
|
||||
}
|
||||
|
||||
// request body data
|
||||
if r.Body == nil {
|
||||
return
|
||||
}
|
||||
var prtBodyBytes []byte
|
||||
var err error
|
||||
|
||||
contentType := r.Header.Get(hdrContentTypeKey)
|
||||
kind := kindOf(r.Body)
|
||||
if canJSONMarshal(contentType, kind) {
|
||||
prtBodyBytes, err = json.MarshalIndent(&r.Body, "", " ")
|
||||
} else if IsXMLType(contentType) && (kind == reflect.Struct) {
|
||||
prtBodyBytes, err = xml.MarshalIndent(&r.Body, "", " ")
|
||||
} else if b, ok := r.Body.(string); ok {
|
||||
if IsJSONType(contentType) {
|
||||
bodyBytes := []byte(b)
|
||||
out := acquireBuffer()
|
||||
defer releaseBuffer(out)
|
||||
if err = json.Indent(out, bodyBytes, "", " "); err == nil {
|
||||
prtBodyBytes = out.Bytes()
|
||||
}
|
||||
} else {
|
||||
body = b
|
||||
}
|
||||
} else if b, ok := r.Body.([]byte); ok {
|
||||
body = fmt.Sprintf("***** BODY IS byte(s) (size - %d) *****", len(b))
|
||||
return
|
||||
}
|
||||
|
||||
if prtBodyBytes != nil && err == nil {
|
||||
body = string(prtBodyBytes)
|
||||
}
|
||||
|
||||
if len(body) > 0 {
|
||||
bodySize := int64(len([]byte(body)))
|
||||
if bodySize > sl {
|
||||
body = fmt.Sprintf("***** REQUEST TOO LARGE (size - %d) *****", bodySize)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Request) selectAddr(addrs []*net.SRV, path string, attempt int) string {
|
||||
if addrs == nil {
|
||||
return path
|
||||
}
|
||||
|
||||
idx := attempt % len(addrs)
|
||||
domain := strings.TrimRight(addrs[idx].Target, ".")
|
||||
path = strings.TrimLeft(path, "/")
|
||||
|
||||
return fmt.Sprintf("%s://%s:%d/%s", r.client.scheme, domain, addrs[idx].Port, path)
|
||||
}
|
||||
|
||||
func (r *Request) initValuesMap() {
|
||||
if r.values == nil {
|
||||
r.values = make(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var noescapeJSONMarshal = func(v interface{}) (*bytes.Buffer, error) {
|
||||
buf := acquireBuffer()
|
||||
encoder := json.NewEncoder(buf)
|
||||
encoder.SetEscapeHTML(false)
|
||||
if err := encoder.Encode(v); err != nil {
|
||||
releaseBuffer(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
175
vendor/github.com/go-resty/resty/v2/response.go
generated
vendored
175
vendor/github.com/go-resty/resty/v2/response.go
generated
vendored
|
|
@ -1,175 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response struct and methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Response struct holds response values of executed request.
|
||||
type Response struct {
|
||||
Request *Request
|
||||
RawResponse *http.Response
|
||||
|
||||
body []byte
|
||||
size int64
|
||||
receivedAt time.Time
|
||||
}
|
||||
|
||||
// Body method returns HTTP response as []byte array for the executed request.
|
||||
//
|
||||
// Note: `Response.Body` might be nil, if `Request.SetOutput` is used.
|
||||
func (r *Response) Body() []byte {
|
||||
if r.RawResponse == nil {
|
||||
return []byte{}
|
||||
}
|
||||
return r.body
|
||||
}
|
||||
|
||||
// Status method returns the HTTP status string for the executed request.
|
||||
// Example: 200 OK
|
||||
func (r *Response) Status() string {
|
||||
if r.RawResponse == nil {
|
||||
return ""
|
||||
}
|
||||
return r.RawResponse.Status
|
||||
}
|
||||
|
||||
// StatusCode method returns the HTTP status code for the executed request.
|
||||
// Example: 200
|
||||
func (r *Response) StatusCode() int {
|
||||
if r.RawResponse == nil {
|
||||
return 0
|
||||
}
|
||||
return r.RawResponse.StatusCode
|
||||
}
|
||||
|
||||
// Proto method returns the HTTP response protocol used for the request.
|
||||
func (r *Response) Proto() string {
|
||||
if r.RawResponse == nil {
|
||||
return ""
|
||||
}
|
||||
return r.RawResponse.Proto
|
||||
}
|
||||
|
||||
// Result method returns the response value as an object if it has one
|
||||
func (r *Response) Result() interface{} {
|
||||
return r.Request.Result
|
||||
}
|
||||
|
||||
// Error method returns the error object if it has one
|
||||
func (r *Response) Error() interface{} {
|
||||
return r.Request.Error
|
||||
}
|
||||
|
||||
// Header method returns the response headers
|
||||
func (r *Response) Header() http.Header {
|
||||
if r.RawResponse == nil {
|
||||
return http.Header{}
|
||||
}
|
||||
return r.RawResponse.Header
|
||||
}
|
||||
|
||||
// Cookies method to access all the response cookies
|
||||
func (r *Response) Cookies() []*http.Cookie {
|
||||
if r.RawResponse == nil {
|
||||
return make([]*http.Cookie, 0)
|
||||
}
|
||||
return r.RawResponse.Cookies()
|
||||
}
|
||||
|
||||
// String method returns the body of the server response as String.
|
||||
func (r *Response) String() string {
|
||||
if r.body == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(r.body))
|
||||
}
|
||||
|
||||
// Time method returns the time of HTTP response time that from request we sent and received a request.
|
||||
//
|
||||
// See `Response.ReceivedAt` to know when client received response and see `Response.Request.Time` to know
|
||||
// when client sent a request.
|
||||
func (r *Response) Time() time.Duration {
|
||||
if r.Request.clientTrace != nil {
|
||||
return r.Request.TraceInfo().TotalTime
|
||||
}
|
||||
return r.receivedAt.Sub(r.Request.Time)
|
||||
}
|
||||
|
||||
// ReceivedAt method returns when response got received from server for the request.
|
||||
func (r *Response) ReceivedAt() time.Time {
|
||||
return r.receivedAt
|
||||
}
|
||||
|
||||
// Size method returns the HTTP response size in bytes. Ya, you can relay on HTTP `Content-Length` header,
|
||||
// however it won't be good for chucked transfer/compressed response. Since Resty calculates response size
|
||||
// at the client end. You will get actual size of the http response.
|
||||
func (r *Response) Size() int64 {
|
||||
return r.size
|
||||
}
|
||||
|
||||
// RawBody method exposes the HTTP raw response body. Use this method in-conjunction with `SetDoNotParseResponse`
|
||||
// option otherwise you get an error as `read err: http: read on closed response body`.
|
||||
//
|
||||
// Do not forget to close the body, otherwise you might get into connection leaks, no connection reuse.
|
||||
// Basically you have taken over the control of response parsing from `Resty`.
|
||||
func (r *Response) RawBody() io.ReadCloser {
|
||||
if r.RawResponse == nil {
|
||||
return nil
|
||||
}
|
||||
return r.RawResponse.Body
|
||||
}
|
||||
|
||||
// IsSuccess method returns true if HTTP status `code >= 200 and <= 299` otherwise false.
|
||||
func (r *Response) IsSuccess() bool {
|
||||
return r.StatusCode() > 199 && r.StatusCode() < 300
|
||||
}
|
||||
|
||||
// IsError method returns true if HTTP status `code >= 400` otherwise false.
|
||||
func (r *Response) IsError() bool {
|
||||
return r.StatusCode() > 399
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Response Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func (r *Response) setReceivedAt() {
|
||||
r.receivedAt = time.Now()
|
||||
if r.Request.clientTrace != nil {
|
||||
r.Request.clientTrace.endTime = r.receivedAt
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Response) fmtBodyString(sl int64) string {
|
||||
if r.body != nil {
|
||||
if int64(len(r.body)) > sl {
|
||||
return fmt.Sprintf("***** RESPONSE TOO LARGE (size - %d) *****", len(r.body))
|
||||
}
|
||||
ct := r.Header().Get(hdrContentTypeKey)
|
||||
if IsJSONType(ct) {
|
||||
out := acquireBuffer()
|
||||
defer releaseBuffer(out)
|
||||
err := json.Indent(out, r.body, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Sprintf("*** Error: Unable to format response body - \"%s\" ***\n\nLog Body as-is:\n%s", err, r.String())
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
return r.String()
|
||||
}
|
||||
|
||||
return "***** NO CONTENT *****"
|
||||
}
|
||||
40
vendor/github.com/go-resty/resty/v2/resty.go
generated
vendored
40
vendor/github.com/go-resty/resty/v2/resty.go
generated
vendored
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package resty provides Simple HTTP and REST client library for Go.
|
||||
package resty
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
|
||||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
// Version # of resty
|
||||
const Version = "2.7.0"
|
||||
|
||||
// New method creates a new Resty client.
|
||||
func New() *Client {
|
||||
cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
return createClient(&http.Client{
|
||||
Jar: cookieJar,
|
||||
})
|
||||
}
|
||||
|
||||
// NewWithClient method creates a new Resty client with given `http.Client`.
|
||||
func NewWithClient(hc *http.Client) *Client {
|
||||
return createClient(hc)
|
||||
}
|
||||
|
||||
// NewWithLocalAddr method creates a new Resty client with given Local Address
|
||||
// to dial from.
|
||||
func NewWithLocalAddr(localAddr net.Addr) *Client {
|
||||
cookieJar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||
return createClient(&http.Client{
|
||||
Jar: cookieJar,
|
||||
Transport: createTransport(localAddr),
|
||||
})
|
||||
}
|
||||
221
vendor/github.com/go-resty/resty/v2/retry.go
generated
vendored
221
vendor/github.com/go-resty/resty/v2/retry.go
generated
vendored
|
|
@ -1,221 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxRetries = 3
|
||||
defaultWaitTime = time.Duration(100) * time.Millisecond
|
||||
defaultMaxWaitTime = time.Duration(2000) * time.Millisecond
|
||||
)
|
||||
|
||||
type (
|
||||
// Option is to create convenient retry options like wait time, max retries, etc.
|
||||
Option func(*Options)
|
||||
|
||||
// RetryConditionFunc type is for retry condition function
|
||||
// input: non-nil Response OR request execution error
|
||||
RetryConditionFunc func(*Response, error) bool
|
||||
|
||||
// OnRetryFunc is for side-effecting functions triggered on retry
|
||||
OnRetryFunc func(*Response, error)
|
||||
|
||||
// RetryAfterFunc returns time to wait before retry
|
||||
// For example, it can parse HTTP Retry-After header
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
// Non-nil error is returned if it is found that request is not retryable
|
||||
// (0, nil) is a special result means 'use default algorithm'
|
||||
RetryAfterFunc func(*Client, *Response) (time.Duration, error)
|
||||
|
||||
// Options struct is used to hold retry settings.
|
||||
Options struct {
|
||||
maxRetries int
|
||||
waitTime time.Duration
|
||||
maxWaitTime time.Duration
|
||||
retryConditions []RetryConditionFunc
|
||||
retryHooks []OnRetryFunc
|
||||
}
|
||||
)
|
||||
|
||||
// Retries sets the max number of retries
|
||||
func Retries(value int) Option {
|
||||
return func(o *Options) {
|
||||
o.maxRetries = value
|
||||
}
|
||||
}
|
||||
|
||||
// WaitTime sets the default wait time to sleep between requests
|
||||
func WaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.waitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// MaxWaitTime sets the max wait time to sleep between requests
|
||||
func MaxWaitTime(value time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.maxWaitTime = value
|
||||
}
|
||||
}
|
||||
|
||||
// RetryConditions sets the conditions that will be checked for retry.
|
||||
func RetryConditions(conditions []RetryConditionFunc) Option {
|
||||
return func(o *Options) {
|
||||
o.retryConditions = conditions
|
||||
}
|
||||
}
|
||||
|
||||
// RetryHooks sets the hooks that will be executed after each retry
|
||||
func RetryHooks(hooks []OnRetryFunc) Option {
|
||||
return func(o *Options) {
|
||||
o.retryHooks = hooks
|
||||
}
|
||||
}
|
||||
|
||||
// Backoff retries with increasing timeout duration up until X amount of retries
|
||||
// (Default is 3 attempts, Override with option Retries(n))
|
||||
func Backoff(operation func() (*Response, error), options ...Option) error {
|
||||
// Defaults
|
||||
opts := Options{
|
||||
maxRetries: defaultMaxRetries,
|
||||
waitTime: defaultWaitTime,
|
||||
maxWaitTime: defaultMaxWaitTime,
|
||||
retryConditions: []RetryConditionFunc{},
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
var (
|
||||
resp *Response
|
||||
err error
|
||||
)
|
||||
|
||||
for attempt := 0; attempt <= opts.maxRetries; attempt++ {
|
||||
resp, err = operation()
|
||||
ctx := context.Background()
|
||||
if resp != nil && resp.Request.ctx != nil {
|
||||
ctx = resp.Request.ctx
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err1 := unwrapNoRetryErr(err) // raw error, it used for return users callback.
|
||||
needsRetry := err != nil && err == err1 // retry on a few operation errors by default
|
||||
|
||||
for _, condition := range opts.retryConditions {
|
||||
needsRetry = condition(resp, err1)
|
||||
if needsRetry {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !needsRetry {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, hook := range opts.retryHooks {
|
||||
hook(resp, err)
|
||||
}
|
||||
|
||||
// Don't need to wait when no retries left.
|
||||
// Still run retry hooks even on last retry to keep compatibility.
|
||||
if attempt == opts.maxRetries {
|
||||
return err
|
||||
}
|
||||
|
||||
waitTime, err2 := sleepDuration(resp, opts.waitTime, opts.maxWaitTime, attempt)
|
||||
if err2 != nil {
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(waitTime):
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func sleepDuration(resp *Response, min, max time.Duration, attempt int) (time.Duration, error) {
|
||||
const maxInt = 1<<31 - 1 // max int for arch 386
|
||||
if max < 0 {
|
||||
max = maxInt
|
||||
}
|
||||
if resp == nil {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
|
||||
retryAfterFunc := resp.Request.client.RetryAfter
|
||||
|
||||
// Check for custom callback
|
||||
if retryAfterFunc == nil {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
|
||||
result, err := retryAfterFunc(resp.Request.client, resp)
|
||||
if err != nil {
|
||||
return 0, err // i.e. 'API quota exceeded'
|
||||
}
|
||||
if result == 0 {
|
||||
return jitterBackoff(min, max, attempt), nil
|
||||
}
|
||||
if result < 0 || max < result {
|
||||
result = max
|
||||
}
|
||||
if result < min {
|
||||
result = min
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Return capped exponential backoff with jitter
|
||||
// http://www.awsarchitectureblog.com/2015/03/backoff.html
|
||||
func jitterBackoff(min, max time.Duration, attempt int) time.Duration {
|
||||
base := float64(min)
|
||||
capLevel := float64(max)
|
||||
|
||||
temp := math.Min(capLevel, base*math.Exp2(float64(attempt)))
|
||||
ri := time.Duration(temp / 2)
|
||||
result := randDuration(ri)
|
||||
|
||||
if result < min {
|
||||
result = min
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var rnd = newRnd()
|
||||
var rndMu sync.Mutex
|
||||
|
||||
func randDuration(center time.Duration) time.Duration {
|
||||
rndMu.Lock()
|
||||
defer rndMu.Unlock()
|
||||
|
||||
var ri = int64(center)
|
||||
var jitter = rnd.Int63n(ri)
|
||||
return time.Duration(math.Abs(float64(ri + jitter)))
|
||||
}
|
||||
|
||||
func newRnd() *rand.Rand {
|
||||
var seed = time.Now().UnixNano()
|
||||
var src = rand.NewSource(seed)
|
||||
return rand.New(src)
|
||||
}
|
||||
130
vendor/github.com/go-resty/resty/v2/trace.go
generated
vendored
130
vendor/github.com/go-resty/resty/v2/trace.go
generated
vendored
|
|
@ -1,130 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http/httptrace"
|
||||
"time"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// TraceInfo struct
|
||||
//_______________________________________________________________________
|
||||
|
||||
// TraceInfo struct is used provide request trace info such as DNS lookup
|
||||
// duration, Connection obtain duration, Server processing duration, etc.
|
||||
//
|
||||
// Since v2.0.0
|
||||
type TraceInfo struct {
|
||||
// DNSLookup is a duration that transport took to perform
|
||||
// DNS lookup.
|
||||
DNSLookup time.Duration
|
||||
|
||||
// ConnTime is a duration that took to obtain a successful connection.
|
||||
ConnTime time.Duration
|
||||
|
||||
// TCPConnTime is a duration that took to obtain the TCP connection.
|
||||
TCPConnTime time.Duration
|
||||
|
||||
// TLSHandshake is a duration that TLS handshake took place.
|
||||
TLSHandshake time.Duration
|
||||
|
||||
// ServerTime is a duration that server took to respond first byte.
|
||||
ServerTime time.Duration
|
||||
|
||||
// ResponseTime is a duration since first response byte from server to
|
||||
// request completion.
|
||||
ResponseTime time.Duration
|
||||
|
||||
// TotalTime is a duration that total request took end-to-end.
|
||||
TotalTime time.Duration
|
||||
|
||||
// IsConnReused is whether this connection has been previously
|
||||
// used for another HTTP request.
|
||||
IsConnReused bool
|
||||
|
||||
// IsConnWasIdle is whether this connection was obtained from an
|
||||
// idle pool.
|
||||
IsConnWasIdle bool
|
||||
|
||||
// ConnIdleTime is a duration how long the connection was previously
|
||||
// idle, if IsConnWasIdle is true.
|
||||
ConnIdleTime time.Duration
|
||||
|
||||
// RequestAttempt is to represent the request attempt made during a Resty
|
||||
// request execution flow, including retry count.
|
||||
RequestAttempt int
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
RemoteAddr net.Addr
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// ClientTrace struct and its methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// tracer struct maps the `httptrace.ClientTrace` hooks into Fields
|
||||
// with same naming for easy understanding. Plus additional insights
|
||||
// Request.
|
||||
type clientTrace struct {
|
||||
getConn time.Time
|
||||
dnsStart time.Time
|
||||
dnsDone time.Time
|
||||
connectDone time.Time
|
||||
tlsHandshakeStart time.Time
|
||||
tlsHandshakeDone time.Time
|
||||
gotConn time.Time
|
||||
gotFirstResponseByte time.Time
|
||||
endTime time.Time
|
||||
gotConnInfo httptrace.GotConnInfo
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Trace unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
func (t *clientTrace) createContext(ctx context.Context) context.Context {
|
||||
return httptrace.WithClientTrace(
|
||||
ctx,
|
||||
&httptrace.ClientTrace{
|
||||
DNSStart: func(_ httptrace.DNSStartInfo) {
|
||||
t.dnsStart = time.Now()
|
||||
},
|
||||
DNSDone: func(_ httptrace.DNSDoneInfo) {
|
||||
t.dnsDone = time.Now()
|
||||
},
|
||||
ConnectStart: func(_, _ string) {
|
||||
if t.dnsDone.IsZero() {
|
||||
t.dnsDone = time.Now()
|
||||
}
|
||||
if t.dnsStart.IsZero() {
|
||||
t.dnsStart = t.dnsDone
|
||||
}
|
||||
},
|
||||
ConnectDone: func(net, addr string, err error) {
|
||||
t.connectDone = time.Now()
|
||||
},
|
||||
GetConn: func(_ string) {
|
||||
t.getConn = time.Now()
|
||||
},
|
||||
GotConn: func(ci httptrace.GotConnInfo) {
|
||||
t.gotConn = time.Now()
|
||||
t.gotConnInfo = ci
|
||||
},
|
||||
GotFirstResponseByte: func() {
|
||||
t.gotFirstResponseByte = time.Now()
|
||||
},
|
||||
TLSHandshakeStart: func() {
|
||||
t.tlsHandshakeStart = time.Now()
|
||||
},
|
||||
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
|
||||
t.tlsHandshakeDone = time.Now()
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
35
vendor/github.com/go-resty/resty/v2/transport.go
generated
vendored
35
vendor/github.com/go-resty/resty/v2/transport.go
generated
vendored
|
|
@ -1,35 +0,0 @@
|
|||
// +build go1.13
|
||||
|
||||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func createTransport(localAddr net.Addr) *http.Transport {
|
||||
dialer := &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}
|
||||
if localAddr != nil {
|
||||
dialer.LocalAddr = localAddr
|
||||
}
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dialer.DialContext,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
}
|
||||
34
vendor/github.com/go-resty/resty/v2/transport112.go
generated
vendored
34
vendor/github.com/go-resty/resty/v2/transport112.go
generated
vendored
|
|
@ -1,34 +0,0 @@
|
|||
// +build !go1.13
|
||||
|
||||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func createTransport(localAddr net.Addr) *http.Transport {
|
||||
dialer := &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}
|
||||
if localAddr != nil {
|
||||
dialer.LocalAddr = localAddr
|
||||
}
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dialer.DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
}
|
||||
391
vendor/github.com/go-resty/resty/v2/util.go
generated
vendored
391
vendor/github.com/go-resty/resty/v2/util.go
generated
vendored
|
|
@ -1,391 +0,0 @@
|
|||
// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
|
||||
// resty source code and usage is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package resty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Logger interface
|
||||
//_______________________________________________________________________
|
||||
|
||||
// Logger interface is to abstract the logging from Resty. Gives control to
|
||||
// the Resty users, choice of the logger.
|
||||
type Logger interface {
|
||||
Errorf(format string, v ...interface{})
|
||||
Warnf(format string, v ...interface{})
|
||||
Debugf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
func createLogger() *logger {
|
||||
l := &logger{l: log.New(os.Stderr, "", log.Ldate|log.Lmicroseconds)}
|
||||
return l
|
||||
}
|
||||
|
||||
var _ Logger = (*logger)(nil)
|
||||
|
||||
type logger struct {
|
||||
l *log.Logger
|
||||
}
|
||||
|
||||
func (l *logger) Errorf(format string, v ...interface{}) {
|
||||
l.output("ERROR RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Warnf(format string, v ...interface{}) {
|
||||
l.output("WARN RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) Debugf(format string, v ...interface{}) {
|
||||
l.output("DEBUG RESTY "+format, v...)
|
||||
}
|
||||
|
||||
func (l *logger) output(format string, v ...interface{}) {
|
||||
if len(v) == 0 {
|
||||
l.l.Print(format)
|
||||
return
|
||||
}
|
||||
l.l.Printf(format, v...)
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Helper methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// IsStringEmpty method tells whether given string is empty or not
|
||||
func IsStringEmpty(str string) bool {
|
||||
return len(strings.TrimSpace(str)) == 0
|
||||
}
|
||||
|
||||
// DetectContentType method is used to figure out `Request.Body` content type for request header
|
||||
func DetectContentType(body interface{}) string {
|
||||
contentType := plainTextType
|
||||
kind := kindOf(body)
|
||||
switch kind {
|
||||
case reflect.Struct, reflect.Map:
|
||||
contentType = jsonContentType
|
||||
case reflect.String:
|
||||
contentType = plainTextType
|
||||
default:
|
||||
if b, ok := body.([]byte); ok {
|
||||
contentType = http.DetectContentType(b)
|
||||
} else if kind == reflect.Slice {
|
||||
contentType = jsonContentType
|
||||
}
|
||||
}
|
||||
|
||||
return contentType
|
||||
}
|
||||
|
||||
// IsJSONType method is to check JSON content type or not
|
||||
func IsJSONType(ct string) bool {
|
||||
return jsonCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// IsXMLType method is to check XML content type or not
|
||||
func IsXMLType(ct string) bool {
|
||||
return xmlCheck.MatchString(ct)
|
||||
}
|
||||
|
||||
// Unmarshalc content into object from JSON or XML
|
||||
func Unmarshalc(c *Client, ct string, b []byte, d interface{}) (err error) {
|
||||
if IsJSONType(ct) {
|
||||
err = c.JSONUnmarshal(b, d)
|
||||
} else if IsXMLType(ct) {
|
||||
err = c.XMLUnmarshal(b, d)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// RequestLog and ResponseLog type
|
||||
//_______________________________________________________________________
|
||||
|
||||
// RequestLog struct is used to collected information from resty request
|
||||
// instance for debug logging. It sent to request log callback before resty
|
||||
// actually logs the information.
|
||||
type RequestLog struct {
|
||||
Header http.Header
|
||||
Body string
|
||||
}
|
||||
|
||||
// ResponseLog struct is used to collected information from resty response
|
||||
// instance for debug logging. It sent to response log callback before resty
|
||||
// actually logs the information.
|
||||
type ResponseLog struct {
|
||||
Header http.Header
|
||||
Body string
|
||||
}
|
||||
|
||||
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|
||||
// Package Unexported methods
|
||||
//_______________________________________________________________________
|
||||
|
||||
// way to disable the HTML escape as opt-in
|
||||
func jsonMarshal(c *Client, r *Request, d interface{}) (*bytes.Buffer, error) {
|
||||
if !r.jsonEscapeHTML || !c.jsonEscapeHTML {
|
||||
return noescapeJSONMarshal(d)
|
||||
}
|
||||
|
||||
data, err := c.JSONMarshal(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := acquireBuffer()
|
||||
_, _ = buf.Write(data)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func firstNonEmpty(v ...string) string {
|
||||
for _, s := range v {
|
||||
if !IsStringEmpty(s) {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
func escapeQuotes(s string) string {
|
||||
return quoteEscaper.Replace(s)
|
||||
}
|
||||
|
||||
func createMultipartHeader(param, fileName, contentType string) textproto.MIMEHeader {
|
||||
hdr := make(textproto.MIMEHeader)
|
||||
|
||||
var contentDispositionValue string
|
||||
if IsStringEmpty(fileName) {
|
||||
contentDispositionValue = fmt.Sprintf(`form-data; name="%s"`, param)
|
||||
} else {
|
||||
contentDispositionValue = fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
|
||||
param, escapeQuotes(fileName))
|
||||
}
|
||||
hdr.Set("Content-Disposition", contentDispositionValue)
|
||||
|
||||
if !IsStringEmpty(contentType) {
|
||||
hdr.Set(hdrContentTypeKey, contentType)
|
||||
}
|
||||
return hdr
|
||||
}
|
||||
|
||||
func addMultipartFormField(w *multipart.Writer, mf *MultipartField) error {
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(mf.Param, mf.FileName, mf.ContentType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, mf.Reader)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeMultipartFormFile(w *multipart.Writer, fieldName, fileName string, r io.Reader) error {
|
||||
// Auto detect actual multipart content type
|
||||
cbuf := make([]byte, 512)
|
||||
size, err := r.Read(cbuf)
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
partWriter, err := w.CreatePart(createMultipartHeader(fieldName, fileName, http.DetectContentType(cbuf)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = partWriter.Write(cbuf[:size]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(partWriter, r)
|
||||
return err
|
||||
}
|
||||
|
||||
func addFile(w *multipart.Writer, fieldName, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeq(file)
|
||||
return writeMultipartFormFile(w, fieldName, filepath.Base(path), file)
|
||||
}
|
||||
|
||||
func addFileReader(w *multipart.Writer, f *File) error {
|
||||
return writeMultipartFormFile(w, f.ParamName, f.Name, f.Reader)
|
||||
}
|
||||
|
||||
func getPointer(v interface{}) interface{} {
|
||||
vv := valueOf(v)
|
||||
if vv.Kind() == reflect.Ptr {
|
||||
return v
|
||||
}
|
||||
return reflect.New(vv.Type()).Interface()
|
||||
}
|
||||
|
||||
func isPayloadSupported(m string, allowMethodGet bool) bool {
|
||||
return !(m == MethodHead || m == MethodOptions || (m == MethodGet && !allowMethodGet))
|
||||
}
|
||||
|
||||
func typeOf(i interface{}) reflect.Type {
|
||||
return indirect(valueOf(i)).Type()
|
||||
}
|
||||
|
||||
func valueOf(i interface{}) reflect.Value {
|
||||
return reflect.ValueOf(i)
|
||||
}
|
||||
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
return reflect.Indirect(v)
|
||||
}
|
||||
|
||||
func kindOf(v interface{}) reflect.Kind {
|
||||
return typeOf(v).Kind()
|
||||
}
|
||||
|
||||
func createDirectory(dir string) (err error) {
|
||||
if _, err = os.Stat(dir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func canJSONMarshal(contentType string, kind reflect.Kind) bool {
|
||||
return IsJSONType(contentType) && (kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice)
|
||||
}
|
||||
|
||||
func functionName(i interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
|
||||
}
|
||||
|
||||
func acquireBuffer() *bytes.Buffer {
|
||||
return bufPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func releaseBuffer(buf *bytes.Buffer) {
|
||||
if buf != nil {
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
}
|
||||
}
|
||||
|
||||
// requestBodyReleaser wraps requests's body and implements custom Close for it.
|
||||
// The Close method closes original body and releases request body back to sync.Pool.
|
||||
type requestBodyReleaser struct {
|
||||
releaseOnce sync.Once
|
||||
reqBuf *bytes.Buffer
|
||||
io.ReadCloser
|
||||
}
|
||||
|
||||
func newRequestBodyReleaser(respBody io.ReadCloser, reqBuf *bytes.Buffer) io.ReadCloser {
|
||||
if reqBuf == nil {
|
||||
return respBody
|
||||
}
|
||||
|
||||
return &requestBodyReleaser{
|
||||
reqBuf: reqBuf,
|
||||
ReadCloser: respBody,
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *requestBodyReleaser) Close() error {
|
||||
err := rr.ReadCloser.Close()
|
||||
rr.releaseOnce.Do(func() {
|
||||
releaseBuffer(rr.reqBuf)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func closeq(v interface{}) {
|
||||
if c, ok := v.(io.Closer); ok {
|
||||
silently(c.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func silently(_ ...interface{}) {}
|
||||
|
||||
func composeHeaders(c *Client, r *Request, hdrs http.Header) string {
|
||||
str := make([]string, 0, len(hdrs))
|
||||
for _, k := range sortHeaderKeys(hdrs) {
|
||||
var v string
|
||||
if k == "Cookie" {
|
||||
cv := strings.TrimSpace(strings.Join(hdrs[k], ", "))
|
||||
if c.GetClient().Jar != nil {
|
||||
for _, c := range c.GetClient().Jar.Cookies(r.RawRequest.URL) {
|
||||
if cv != "" {
|
||||
cv = cv + "; " + c.String()
|
||||
} else {
|
||||
cv = c.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
v = strings.TrimSpace(fmt.Sprintf("%25s: %s", k, cv))
|
||||
} else {
|
||||
v = strings.TrimSpace(fmt.Sprintf("%25s: %s", k, strings.Join(hdrs[k], ", ")))
|
||||
}
|
||||
if v != "" {
|
||||
str = append(str, "\t"+v)
|
||||
}
|
||||
}
|
||||
return strings.Join(str, "\n")
|
||||
}
|
||||
|
||||
func sortHeaderKeys(hdrs http.Header) []string {
|
||||
keys := make([]string, 0, len(hdrs))
|
||||
for key := range hdrs {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func copyHeaders(hdrs http.Header) http.Header {
|
||||
nh := http.Header{}
|
||||
for k, v := range hdrs {
|
||||
nh[k] = v
|
||||
}
|
||||
return nh
|
||||
}
|
||||
|
||||
type noRetryErr struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *noRetryErr) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func wrapNoRetryErr(err error) error {
|
||||
if err != nil {
|
||||
err = &noRetryErr{err: err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func unwrapNoRetryErr(err error) error {
|
||||
if e, ok := err.(*noRetryErr); ok {
|
||||
err = e.err
|
||||
}
|
||||
return err
|
||||
}
|
||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
|
|
@ -129,9 +129,6 @@ github.com/go-openapi/swag
|
|||
# github.com/go-openapi/validate v0.22.1
|
||||
## explicit; go 1.14
|
||||
github.com/go-openapi/validate
|
||||
# github.com/go-resty/resty/v2 v2.7.0
|
||||
## explicit; go 1.11
|
||||
github.com/go-resty/resty/v2
|
||||
# github.com/go-sql-driver/mysql v1.7.0
|
||||
## explicit; go 1.13
|
||||
github.com/go-sql-driver/mysql
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue