github.com/phrase/openapi@v0.0.0-20240514140800-49e8a106740e/openapi-generator/templates/go/response.mustache (about)

     1  package {{packageName}}
     2  
     3  import (
     4  	"net/http"
     5  	"net/url"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  const (
    12  	headerRateLimit     = "X-Rate-Limit-Limit"
    13  	headerRateRemaining = "X-Rate-Limit-Remaining"
    14  	headerRateReset     = "X-Rate-Limit-Reset"
    15  )
    16  
    17  // Timestamp represents a time that can be unmarshalled from a JSON string
    18  // formatted as either an RFC3339 or Unix timestamp. This is necessary for some
    19  // fields since the GitHub API is inconsistent in how it represents times. All
    20  // exported methods of time.Time can be called on Timestamp.
    21  type Timestamp struct {
    22  	time.Time
    23  }
    24  
    25  func (t Timestamp) String() string {
    26  	return t.Time.String()
    27  }
    28  
    29  // UnmarshalJSON implements the json.Unmarshaler interface.
    30  // Time is expected in RFC3339 or Unix format.
    31  func (t *Timestamp) UnmarshalJSON(data []byte) (err error) {
    32  	str := string(data)
    33  	i, err := strconv.ParseInt(str, 10, 64)
    34  	if err == nil {
    35  		t.Time = time.Unix(i, 0)
    36  	} else {
    37  		t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str)
    38  	}
    39  	return
    40  }
    41  
    42  // Equal reports whether t and u are equal based on time.Equal
    43  func (t Timestamp) Equal(u Timestamp) bool {
    44  	return t.Time.Equal(u.Time)
    45  }
    46  
    47  // Rate represents the rate limit for the current client.
    48  type Rate struct {
    49  	// The number of requests per hour the client is currently limited to.
    50  	Limit int `json:"limit"`
    51  
    52  	// The number of remaining requests the client can make this hour.
    53  	Remaining int `json:"remaining"`
    54  
    55  	// The time at which the current rate limit will reset.
    56  	Reset Timestamp `json:"reset"`
    57  }
    58  
    59  // APIResponse stores the API response returned by the server.
    60  type APIResponse struct {
    61  	*http.Response
    62  
    63  	// These fields provide the page values for paginating through a set of
    64  	// results. Any or all of these may be set to the zero value for
    65  	// responses that are not part of a paginated set, or for which there
    66  	// are no additional pages.
    67  	//
    68  	// These fields support what is called "offset pagination" and should
    69  	// be used with the ListOptions struct.
    70  	NextPage  int
    71  	FirstPage int
    72  	LastPage  int
    73  
    74  	// Explicitly specify the Rate type so Rate's String() receiver doesn't
    75  	// propagate to Response.
    76  	Rate Rate
    77  }
    78  
    79  // populatePageValues parses the HTTP Link response headers and populates the
    80  // various pagination link values in the Response.
    81  func (r *APIResponse) populatePageValues() {
    82  	if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
    83  		for _, link := range strings.Split(links[0], ",") {
    84  			segments := strings.Split(strings.TrimSpace(link), ";")
    85  
    86  			// link must at least have href and rel
    87  			if len(segments) < 2 {
    88  				continue
    89  			}
    90  
    91  			// ensure href is properly formatted
    92  			if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
    93  				continue
    94  			}
    95  
    96  			// try to pull out page parameter
    97  			url, err := url.Parse(segments[0][1 : len(segments[0])-1])
    98  			if err != nil {
    99  				continue
   100  			}
   101  			page := url.Query().Get("page")
   102  			if page == "" {
   103  				continue
   104  			}
   105  
   106  			for _, segment := range segments[1:] {
   107  				switch strings.TrimSpace(segment) {
   108  				case `rel=next`:
   109  					r.NextPage, _ = strconv.Atoi(page)
   110  				case `rel=first`:
   111  					r.FirstPage, _ = strconv.Atoi(page)
   112  				case `rel=last`:
   113  					r.LastPage, _ = strconv.Atoi(page)
   114  				}
   115  
   116  			}
   117  		}
   118  	}
   119  }
   120  
   121  // parseRate parses the rate related headers.
   122  func parseRate(r *http.Response) Rate {
   123  	var rate Rate
   124  	if limit := r.Header.Get(headerRateLimit); limit != "" {
   125  		rate.Limit, _ = strconv.Atoi(limit)
   126  	}
   127  	if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
   128  		rate.Remaining, _ = strconv.Atoi(remaining)
   129  	}
   130  	if reset := r.Header.Get(headerRateReset); reset != "" {
   131  		if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
   132  			rate.Reset = Timestamp{time.Unix(v, 0)}
   133  		}
   134  	}
   135  	return rate
   136  }
   137  
   138  // newResponse creates a new Response for the provided http.Response.
   139  // r must not be nil.
   140  func NewAPIResponse(r *http.Response) *APIResponse {
   141  	response := &APIResponse{Response: r}
   142  	response.populatePageValues()
   143  	response.Rate = parseRate(r)
   144  	return response
   145  }