github.com/gophercloud/gophercloud@v1.11.0/docs/FAQ.md (about)

     1  # Tips
     2  
     3  ## Handling Microversions
     4  
     5  Please see our dedicated document [here](MICROVERSIONS.md).
     6  
     7  ## Implementing default logging and re-authentication attempts
     8  
     9  You can implement custom logging and/or limit re-auth attempts by creating a custom HTTP client
    10  like the following and setting it as the provider client's HTTP Client (via the
    11  `gophercloud.ProviderClient.HTTPClient` field):
    12  
    13  ```go
    14  //...
    15  
    16  // LogRoundTripper satisfies the http.RoundTripper interface and is used to
    17  // customize the default Gophercloud RoundTripper to allow for logging.
    18  type LogRoundTripper struct {
    19  	rt                http.RoundTripper
    20  	numReauthAttempts int
    21  }
    22  
    23  // newHTTPClient return a custom HTTP client that allows for logging relevant
    24  // information before and after the HTTP request.
    25  func newHTTPClient() http.Client {
    26  	return http.Client{
    27  		Transport: &LogRoundTripper{
    28  			rt: http.DefaultTransport,
    29  		},
    30  	}
    31  }
    32  
    33  // RoundTrip performs a round-trip HTTP request and logs relevant information about it.
    34  func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
    35  	glog.Infof("Request URL: %s\n", request.URL)
    36  
    37  	response, err := lrt.rt.RoundTrip(request)
    38  	if response == nil {
    39  		return nil, err
    40  	}
    41  
    42  	if response.StatusCode == http.StatusUnauthorized {
    43  		if lrt.numReauthAttempts == 3 {
    44  			return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.")
    45  		}
    46  		lrt.numReauthAttempts++
    47  	}
    48  
    49  	glog.Debugf("Response Status: %s\n", response.Status)
    50  
    51  	return response, nil
    52  }
    53  
    54  endpoint := "https://127.0.0.1/auth"
    55  pc := openstack.NewClient(endpoint)
    56  pc.HTTPClient = newHTTPClient()
    57  
    58  //...
    59  ```
    60  
    61  
    62  ## Implementing custom objects
    63  
    64  OpenStack request/response objects may differ among variable names or types.
    65  
    66  ### Custom request objects
    67  
    68  To pass custom options to a request, implement the desired `<ACTION>OptsBuilder` interface. For
    69  example, to pass in
    70  
    71  ```go
    72  type MyCreateServerOpts struct {
    73  	Name string
    74  	Size int
    75  }
    76  ```
    77  
    78  to `servers.Create`, simply implement the `servers.CreateOptsBuilder` interface:
    79  
    80  ```go
    81  func (o MyCreateServeropts) ToServerCreateMap() (map[string]interface{}, error) {
    82  	return map[string]interface{}{
    83  		"name": o.Name,
    84  		"size": o.Size,
    85  	}, nil
    86  }
    87  ```
    88  
    89  create an instance of your custom options object, and pass it to `servers.Create`:
    90  
    91  ```go
    92  // ...
    93  myOpts := MyCreateServerOpts{
    94  	Name: "s1",
    95  	Size: "100",
    96  }
    97  server, err := servers.Create(computeClient, myOpts).Extract()
    98  // ...
    99  ```
   100  
   101  ### Custom response objects
   102  
   103  Some OpenStack services have extensions. Extensions that are supported in Gophercloud can be
   104  combined to create a custom object:
   105  
   106  ```go
   107  // ...
   108  type MyVolume struct {
   109    volumes.Volume
   110    tenantattr.VolumeExt
   111  }
   112  
   113  var v struct {
   114    MyVolume `json:"volume"`
   115  }
   116  
   117  err := volumes.Get(client, volID).ExtractInto(&v)
   118  // ...
   119  ```
   120  
   121  ## Overriding default `UnmarshalJSON` method
   122  
   123  For some response objects, a field may be a custom type or may be allowed to take on
   124  different types. In these cases, overriding the default `UnmarshalJSON` method may be
   125  necessary. To do this, declare the JSON `struct` field tag as "-" and create an `UnmarshalJSON`
   126  method on the type:
   127  
   128  ```go
   129  // ...
   130  type MyVolume struct {
   131  	ID string `json: "id"`
   132  	TimeCreated time.Time `json: "-"`
   133  }
   134  
   135  func (r *MyVolume) UnmarshalJSON(b []byte) error {
   136  	type tmp MyVolume
   137  	var s struct {
   138  		tmp
   139  		TimeCreated gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
   140  	}
   141  	err := json.Unmarshal(b, &s)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	*r = Volume(s.tmp)
   146  
   147  	r.TimeCreated = time.Time(s.CreatedAt)
   148  
   149  	return err
   150  }
   151  // ...
   152  ```