github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/service_client.go (about)

     1  package gophercloud
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"net/http"
     7  	"strings"
     8  )
     9  
    10  // ServiceClient stores details required to interact with a specific service API implemented by a provider.
    11  // Generally, you'll acquire these by calling the appropriate `New` method on a ProviderClient.
    12  type ServiceClient struct {
    13  	// ProviderClient is a reference to the provider that implements this service.
    14  	*ProviderClient
    15  
    16  	// Endpoint is the base URL of the service's API, acquired from a service catalog.
    17  	// It MUST end with a /.
    18  	Endpoint string
    19  
    20  	// ResourceBase is the base URL shared by the resources within a service's API. It should include
    21  	// the API version and, like Endpoint, MUST end with a / if set. If not set, the Endpoint is used
    22  	// as-is, instead.
    23  	ResourceBase string
    24  
    25  	// This is the service client type (e.g. compute, sharev2).
    26  	// NOTE: FOR INTERNAL USE ONLY. DO NOT SET. GOPHERCLOUD WILL SET THIS.
    27  	// It is only exported because it gets set in a different package.
    28  	Type string
    29  
    30  	// The microversion of the service to use. Set this to use a particular microversion.
    31  	Microversion string
    32  
    33  	// MoreHeaders allows users (or Gophercloud) to set service-wide headers on requests. Put another way,
    34  	// values set in this field will be set on all the HTTP requests the service client sends.
    35  	MoreHeaders map[string]string
    36  }
    37  
    38  // ResourceBaseURL returns the base URL of any resources used by this service. It MUST end with a /.
    39  func (client *ServiceClient) ResourceBaseURL() string {
    40  	if client.ResourceBase != "" {
    41  		return client.ResourceBase
    42  	}
    43  	return client.Endpoint
    44  }
    45  
    46  // ServiceURL constructs a URL for a resource belonging to this provider.
    47  func (client *ServiceClient) ServiceURL(parts ...string) string {
    48  	return client.ResourceBaseURL() + strings.Join(parts, "/")
    49  }
    50  
    51  func (client *ServiceClient) initReqOpts(JSONBody any, JSONResponse any, opts *RequestOpts) {
    52  	if v, ok := (JSONBody).(io.Reader); ok {
    53  		opts.RawBody = v
    54  	} else if JSONBody != nil {
    55  		opts.JSONBody = JSONBody
    56  	}
    57  
    58  	if JSONResponse != nil {
    59  		opts.JSONResponse = JSONResponse
    60  	}
    61  }
    62  
    63  // Get calls `Request` with the "GET" HTTP verb.
    64  func (client *ServiceClient) Get(ctx context.Context, url string, JSONResponse any, opts *RequestOpts) (*http.Response, error) {
    65  	if opts == nil {
    66  		opts = new(RequestOpts)
    67  	}
    68  	client.initReqOpts(nil, JSONResponse, opts)
    69  	return client.Request(ctx, "GET", url, opts)
    70  }
    71  
    72  // Post calls `Request` with the "POST" HTTP verb.
    73  func (client *ServiceClient) Post(ctx context.Context, url string, JSONBody any, JSONResponse any, opts *RequestOpts) (*http.Response, error) {
    74  	if opts == nil {
    75  		opts = new(RequestOpts)
    76  	}
    77  	client.initReqOpts(JSONBody, JSONResponse, opts)
    78  	return client.Request(ctx, "POST", url, opts)
    79  }
    80  
    81  // Put calls `Request` with the "PUT" HTTP verb.
    82  func (client *ServiceClient) Put(ctx context.Context, url string, JSONBody any, JSONResponse any, opts *RequestOpts) (*http.Response, error) {
    83  	if opts == nil {
    84  		opts = new(RequestOpts)
    85  	}
    86  	client.initReqOpts(JSONBody, JSONResponse, opts)
    87  	return client.Request(ctx, "PUT", url, opts)
    88  }
    89  
    90  // Patch calls `Request` with the "PATCH" HTTP verb.
    91  func (client *ServiceClient) Patch(ctx context.Context, url string, JSONBody any, JSONResponse any, opts *RequestOpts) (*http.Response, error) {
    92  	if opts == nil {
    93  		opts = new(RequestOpts)
    94  	}
    95  	client.initReqOpts(JSONBody, JSONResponse, opts)
    96  	return client.Request(ctx, "PATCH", url, opts)
    97  }
    98  
    99  // Delete calls `Request` with the "DELETE" HTTP verb.
   100  func (client *ServiceClient) Delete(ctx context.Context, url string, opts *RequestOpts) (*http.Response, error) {
   101  	if opts == nil {
   102  		opts = new(RequestOpts)
   103  	}
   104  	client.initReqOpts(nil, nil, opts)
   105  	return client.Request(ctx, "DELETE", url, opts)
   106  }
   107  
   108  // Head calls `Request` with the "HEAD" HTTP verb.
   109  func (client *ServiceClient) Head(ctx context.Context, url string, opts *RequestOpts) (*http.Response, error) {
   110  	if opts == nil {
   111  		opts = new(RequestOpts)
   112  	}
   113  	client.initReqOpts(nil, nil, opts)
   114  	return client.Request(ctx, "HEAD", url, opts)
   115  }
   116  
   117  func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) {
   118  	switch client.Type {
   119  	case "compute":
   120  		opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
   121  	case "sharev2":
   122  		opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion
   123  	case "volume":
   124  		opts.MoreHeaders["X-OpenStack-Volume-API-Version"] = client.Microversion
   125  	case "baremetal":
   126  		opts.MoreHeaders["X-OpenStack-Ironic-API-Version"] = client.Microversion
   127  	case "baremetal-introspection":
   128  		opts.MoreHeaders["X-OpenStack-Ironic-Inspector-API-Version"] = client.Microversion
   129  	}
   130  
   131  	if client.Type != "" {
   132  		opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion
   133  	}
   134  }
   135  
   136  // Request carries out the HTTP operation for the service client
   137  func (client *ServiceClient) Request(ctx context.Context, method, url string, options *RequestOpts) (*http.Response, error) {
   138  	if options.MoreHeaders == nil {
   139  		options.MoreHeaders = make(map[string]string)
   140  	}
   141  
   142  	if client.Microversion != "" {
   143  		client.setMicroversionHeader(options)
   144  	}
   145  
   146  	if len(client.MoreHeaders) > 0 {
   147  		if options == nil {
   148  			options = new(RequestOpts)
   149  		}
   150  
   151  		for k, v := range client.MoreHeaders {
   152  			options.MoreHeaders[k] = v
   153  		}
   154  	}
   155  	return client.ProviderClient.Request(ctx, method, url, options)
   156  }
   157  
   158  // ParseResponse is a helper function to parse http.Response to constituents.
   159  func ParseResponse(resp *http.Response, err error) (io.ReadCloser, http.Header, error) {
   160  	if resp != nil {
   161  		return resp.Body, resp.Header, err
   162  	}
   163  	return nil, nil, err
   164  }