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 }