github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/FAQ.md (about)

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