| package gophercloud |
| |
| import ( |
| "encoding/json" |
| "net/http" |
| "reflect" |
| |
| "github.com/mitchellh/mapstructure" |
| ) |
| |
| /* |
| Result is an internal type to be used by individual resource packages, but its |
| methods will be available on a wide variety of user-facing embedding types. |
| |
| It acts as a base struct that other Result types, returned from request |
| functions, can embed for convenience. All Results capture basic information |
| from the HTTP transaction that was performed, including the response body, |
| HTTP headers, and any errors that happened. |
| |
| Generally, each Result type will have an Extract method that can be used to |
| further interpret the result's payload in a specific context. Extensions or |
| providers can then provide additional extraction functions to pull out |
| provider- or extension-specific information as well. |
| */ |
| type Result struct { |
| // Body is the payload of the HTTP response from the server. In most cases, |
| // this will be the deserialized JSON structure. |
| Body interface{} |
| |
| // Header contains the HTTP header structure from the original response. |
| Header http.Header |
| |
| // Err is an error that occurred during the operation. It's deferred until |
| // extraction to make it easier to chain the Extract call. |
| Err error |
| } |
| |
| // PrettyPrintJSON creates a string containing the full response body as |
| // pretty-printed JSON. It's useful for capturing test fixtures and for |
| // debugging extraction bugs. If you include its output in an issue related to |
| // a buggy extraction function, we will all love you forever. |
| func (r Result) PrettyPrintJSON() string { |
| pretty, err := json.MarshalIndent(r.Body, "", " ") |
| if err != nil { |
| panic(err.Error()) |
| } |
| return string(pretty) |
| } |
| |
| // ErrResult is an internal type to be used by individual resource packages, but |
| // its methods will be available on a wide variety of user-facing embedding |
| // types. |
| // |
| // It represents results that only contain a potential error and |
| // nothing else. Usually, if the operation executed successfully, the Err field |
| // will be nil; otherwise it will be stocked with a relevant error. Use the |
| // ExtractErr method |
| // to cleanly pull it out. |
| type ErrResult struct { |
| Result |
| } |
| |
| // ExtractErr is a function that extracts error information, or nil, from a result. |
| func (r ErrResult) ExtractErr() error { |
| return r.Err |
| } |
| |
| /* |
| HeaderResult is an internal type to be used by individual resource packages, but |
| its methods will be available on a wide variety of user-facing embedding types. |
| |
| It represents a result that only contains an error (possibly nil) and an |
| http.Header. This is used, for example, by the objectstorage packages in |
| openstack, because most of the operations don't return response bodies, but do |
| have relevant information in headers. |
| */ |
| type HeaderResult struct { |
| Result |
| } |
| |
| // ExtractHeader will return the http.Header and error from the HeaderResult. |
| // |
| // header, err := objects.Create(client, "my_container", objects.CreateOpts{}).ExtractHeader() |
| func (hr HeaderResult) ExtractHeader() (http.Header, error) { |
| return hr.Header, hr.Err |
| } |
| |
| // DecodeHeader is a function that decodes a header (usually of type map[string]interface{}) to |
| // another type (usually a struct). This function is used by the objectstorage package to give |
| // users access to response headers without having to query a map. A DecodeHookFunction is used, |
| // because OpenStack-based clients return header values as arrays (Go slices). |
| func DecodeHeader(from, to interface{}) error { |
| config := &mapstructure.DecoderConfig{ |
| DecodeHook: func(from, to reflect.Kind, data interface{}) (interface{}, error) { |
| if from == reflect.Slice { |
| return data.([]string)[0], nil |
| } |
| return data, nil |
| }, |
| Result: to, |
| WeaklyTypedInput: true, |
| } |
| decoder, err := mapstructure.NewDecoder(config) |
| if err != nil { |
| return err |
| } |
| if err := decoder.Decode(from); err != nil { |
| return err |
| } |
| return nil |
| } |
| |
| // RFC3339Milli describes a common time format used by some API responses. |
| const RFC3339Milli = "2006-01-02T15:04:05.999999Z" |
| |
| /* |
| Link is an internal type to be used in packages of collection resources that are |
| paginated in a certain way. |
| |
| It's a response substructure common to many paginated collection results that is |
| used to point to related pages. Usually, the one we care about is the one with |
| Rel field set to "next". |
| */ |
| type Link struct { |
| Href string `mapstructure:"href"` |
| Rel string `mapstructure:"rel"` |
| } |
| |
| /* |
| ExtractNextURL is an internal function useful for packages of collection |
| resources that are paginated in a certain way. |
| |
| It attempts attempts to extract the "next" URL from slice of Link structs, or |
| "" if no such URL is present. |
| */ |
| func ExtractNextURL(links []Link) (string, error) { |
| var url string |
| |
| for _, l := range links { |
| if l.Rel == "next" { |
| url = l.Href |
| } |
| } |
| |
| if url == "" { |
| return "", nil |
| } |
| |
| return url, nil |
| } |