1
0
Fork 0

[golang] handle paginated requests

This commit is contained in:
Julien Dessaux 2025-02-16 10:00:10 +01:00
parent 66466e161f
commit 3cae67aea4
Signed by: adyxax
GPG key ID: F92E51B86E07177E

View file

@ -9,6 +9,7 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"time" "time"
) )
@ -25,7 +26,13 @@ func (e *APIError) Error() string {
type APIMessage struct { type APIMessage struct {
Data json.RawMessage `json:"data"` Data json.RawMessage `json:"data"`
Error *APIError `json:"error"` Error *APIError `json:"error"`
//meta Meta *Meta `json:"meta"`
}
type Meta struct {
Limit int `json:"limit"`
Page int `json:"page"`
Total int `json:"total"`
} }
type Request struct { type Request struct {
@ -45,30 +52,62 @@ type Response struct {
func (c *Client) Send(method string, uriRef *url.URL, payload any, response any) error { func (c *Client) Send(method string, uriRef *url.URL, payload any, response any) error {
responseChannel := make(chan *Response) responseChannel := make(chan *Response)
c.requestsChannel <- &Request{ uri := c.baseURI.ResolveReference(uriRef)
method: method, query := uri.Query()
payload: payload, query.Add("limit", "20")
priority: 10, page := 1
responseChannel: responseChannel, var rawResponses []json.RawMessage
uri: c.baseURI.ResolveReference(uriRef), for {
} query.Set("page", strconv.Itoa(page))
res := <-responseChannel uri.RawQuery = query.Encode()
if res.Err != nil { c.requestsChannel <- &Request{
return res.Err method: method,
} payload: payload,
err := res.Message.Error priority: 10,
if err != nil { responseChannel: responseChannel,
switch err.Code { uri: uri,
case 4214: }
e := decodeShipInTransitError(err.Data) res := <-responseChannel
time.Sleep(e.SecondsToArrival.Duration() * time.Second) if res.Err != nil {
return c.Send(method, uriRef, payload, response) return res.Err
default: }
if err := res.Message.Error; err != nil {
return err return err
} }
err := res.Message.Error
if err != nil {
switch err.Code {
case 4214:
e := decodeShipInTransitError(err.Data)
time.Sleep(e.SecondsToArrival.Duration() * time.Second)
return c.Send(method, uriRef, payload, response)
default:
return err
}
}
if res.Message.Meta == nil {
// This is not a paginated request, we are done
if err := json.Unmarshal(res.Message.Data, &response); err != nil {
return fmt.Errorf("failed to unmarshal message: %w", err)
}
return nil
}
var oneResponse []json.RawMessage
if err := json.Unmarshal(res.Message.Data, &oneResponse); err != nil {
return fmt.Errorf("failed to unmarshal message: %w", err)
}
rawResponses = append(rawResponses, oneResponse...)
if res.Message.Meta.Limit*res.Message.Meta.Page >= res.Message.Meta.Total {
break
}
page++
} }
if err := json.Unmarshal(res.Message.Data, &response); err != nil { responses, err := json.Marshal(rawResponses)
return fmt.Errorf("failed to unmarshal message: %w", err) if err != nil {
return fmt.Errorf("failed to marshal raw responses to paginated request: %w", err)
}
if err := json.Unmarshal(responses, &response); err != nil {
return fmt.Errorf("failed to unmarshal paginated request responses: %w", err)
} }
return nil return nil
} }