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