Skip to content

Commit 9aa8fba

Browse files
author
stlc-bot
committed
feat(api): configure page_number pagination for the v3 list endpoints
Stainless-Generated-From: b8fa12b79cebbaaefde08f1f51edca776b39c285
1 parent 63f7a7e commit 9aa8fba

13 files changed

Lines changed: 985 additions & 275 deletions

‎README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,34 @@ This library provides some conveniences for working with paginated list endpoint
295295

296296
You can use `.ListAutoPaging()` methods to iterate through items across all pages:
297297

298+
```go
299+
iter := client.Webhooks.ListAutoPaging(context.TODO(), sentdm.WebhookListParams{})
300+
// Automatically fetches more pages as needed.
301+
for iter.Next() {
302+
webhookResponse := iter.Current()
303+
fmt.Printf("%+v\n", webhookResponse)
304+
}
305+
if err := iter.Err(); err != nil {
306+
panic(err.Error())
307+
}
308+
```
309+
298310
Or you can use simple `.List()` methods to fetch a single page and receive a standard response object
299311
with additional helper methods like `.GetNextPage()`, e.g.:
300312

313+
```go
314+
page, err := client.Webhooks.List(context.TODO(), sentdm.WebhookListParams{})
315+
for page != nil {
316+
for _, webhook := range page.Data.Webhooks {
317+
fmt.Printf("%+v\n", webhook)
318+
}
319+
page, err = page.GetNextPage()
320+
}
321+
if err != nil {
322+
panic(err.Error())
323+
}
324+
```
325+
301326
### Errors
302327

303328
When the API returns a non-success status code, we return an error with type

‎api.md‎

Lines changed: 6 additions & 9 deletions
Large diffs are not rendered by default.

‎contact.go‎

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
shimjson "github.com/sentdm/sent-dm-go/internal/encoding/json"
1717
"github.com/sentdm/sent-dm-go/internal/requestconfig"
1818
"github.com/sentdm/sent-dm-go/option"
19+
"github.com/sentdm/sent-dm-go/packages/pagination"
1920
"github.com/sentdm/sent-dm-go/packages/param"
2021
"github.com/sentdm/sent-dm-go/packages/respjson"
2122
)
@@ -101,14 +102,30 @@ func (r *ContactService) Update(ctx context.Context, id string, params ContactUp
101102

102103
// Retrieves a paginated list of contacts for the authenticated customer. Supports
103104
// filtering by search term, channel, or phone number.
104-
func (r *ContactService) List(ctx context.Context, params ContactListParams, opts ...option.RequestOption) (res *ContactListResponse, err error) {
105+
func (r *ContactService) List(ctx context.Context, params ContactListParams, opts ...option.RequestOption) (res *pagination.ContactsPage[ContactResponse], err error) {
106+
var raw *http.Response
105107
if !param.IsOmitted(params.XProfileID) {
106108
opts = append(opts, option.WithHeader("x-profile-id", fmt.Sprintf("%v", params.XProfileID.Value)))
107109
}
108110
opts = slices.Concat(r.Options, opts)
111+
opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
109112
path := "v3/contacts"
110-
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, params, &res, opts...)
111-
return res, err
113+
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
114+
if err != nil {
115+
return nil, err
116+
}
117+
err = cfg.Execute()
118+
if err != nil {
119+
return nil, err
120+
}
121+
res.SetPageConfig(cfg, raw)
122+
return res, nil
123+
}
124+
125+
// Retrieves a paginated list of contacts for the authenticated customer. Supports
126+
// filtering by search term, channel, or phone number.
127+
func (r *ContactService) ListAutoPaging(ctx context.Context, params ContactListParams, opts ...option.RequestOption) *pagination.ContactsPageAutoPager[ContactResponse] {
128+
return pagination.NewContactsPageAutoPager(r.List(ctx, params, opts...))
112129
}
113130

114131
// **Deprecated.** Use `PATCH /v3/contacts/{id}` with `{"opt_out": true}` instead,
@@ -325,54 +342,6 @@ func (r *ContactResponse) UnmarshalJSON(data []byte) error {
325342
return apijson.UnmarshalRoot(data, r)
326343
}
327344

328-
// Standard API response envelope for all v3 endpoints
329-
type ContactListResponse struct {
330-
// A paginated list of contacts.
331-
Data ContactListResponseData `json:"data" api:"nullable"`
332-
// Error information
333-
Error ErrorDetail `json:"error" api:"nullable"`
334-
// Request and response metadata
335-
Meta APIMeta `json:"meta"`
336-
// Indicates whether the request was successful
337-
Success bool `json:"success"`
338-
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
339-
JSON struct {
340-
Data respjson.Field
341-
Error respjson.Field
342-
Meta respjson.Field
343-
Success respjson.Field
344-
ExtraFields map[string]respjson.Field
345-
raw string
346-
} `json:"-"`
347-
}
348-
349-
// Returns the unmodified JSON received from the API
350-
func (r ContactListResponse) RawJSON() string { return r.JSON.raw }
351-
func (r *ContactListResponse) UnmarshalJSON(data []byte) error {
352-
return apijson.UnmarshalRoot(data, r)
353-
}
354-
355-
// A paginated list of contacts.
356-
type ContactListResponseData struct {
357-
// The contacts on this page.
358-
Contacts []ContactResponse `json:"contacts"`
359-
// Pagination metadata for list responses
360-
Pagination PaginationMeta `json:"pagination"`
361-
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
362-
JSON struct {
363-
Contacts respjson.Field
364-
Pagination respjson.Field
365-
ExtraFields map[string]respjson.Field
366-
raw string
367-
} `json:"-"`
368-
}
369-
370-
// Returns the unmodified JSON received from the API
371-
func (r ContactListResponseData) RawJSON() string { return r.JSON.raw }
372-
func (r *ContactListResponseData) UnmarshalJSON(data []byte) error {
373-
return apijson.UnmarshalRoot(data, r)
374-
}
375-
376345
type ContactNewParams struct {
377346
// Phone number of the contact to create
378347
PhoneNumber string `json:"phone_number" api:"required"`
@@ -420,16 +389,16 @@ func (r *ContactUpdateParams) UnmarshalJSON(data []byte) error {
420389
}
421390

422391
type ContactListParams struct {
423-
// Page number (1-indexed)
424-
Page int64 `query:"page" api:"required" json:"-"`
425-
// Number of items per page
426-
PageSize int64 `query:"page_size" api:"required" json:"-"`
427392
// Optional channel filter (sms, whatsapp)
428393
Channel param.Opt[string] `query:"channel,omitzero" json:"-"`
429394
// Optional phone number filter (alternative to list view)
430395
Phone param.Opt[string] `query:"phone,omitzero" json:"-"`
431396
// Optional search term for filtering contacts
432-
Search param.Opt[string] `query:"search,omitzero" json:"-"`
397+
Search param.Opt[string] `query:"search,omitzero" json:"-"`
398+
// Page number (1-indexed)
399+
Page param.Opt[int64] `query:"page,omitzero" json:"-"`
400+
// Number of items per page
401+
PageSize param.Opt[int64] `query:"page_size,omitzero" json:"-"`
433402
XProfileID param.Opt[string] `header:"x-profile-id,omitzero" format:"uuid" json:"-"`
434403
paramObj
435404
}

‎contact_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ func TestContactListWithOptionalParams(t *testing.T) {
117117
option.WithAPIKey("My API Key"),
118118
)
119119
_, err := client.Contacts.List(context.TODO(), sentdm.ContactListParams{
120-
Page: 0,
121-
PageSize: 0,
122120
Channel: sentdm.String("channel"),
121+
Page: sentdm.Int(0),
122+
PageSize: sentdm.Int(0),
123123
Phone: sentdm.String("phone"),
124124
Search: sentdm.String("search"),
125125
XProfileID: sentdm.String("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"),

‎conversation.go‎

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/sentdm/sent-dm-go/internal/apiquery"
1616
"github.com/sentdm/sent-dm-go/internal/requestconfig"
1717
"github.com/sentdm/sent-dm-go/option"
18+
"github.com/sentdm/sent-dm-go/packages/pagination"
1819
"github.com/sentdm/sent-dm-go/packages/param"
1920
"github.com/sentdm/sent-dm-go/packages/respjson"
2021
)
@@ -49,30 +50,62 @@ func NewConversationService(opts ...option.RequestOption) (r ConversationService
4950

5051
// Retrieves a paginated list of the authenticated customer's messages across all
5152
// conversations, ordered by created date (most recent first).
52-
func (r *ConversationService) List(ctx context.Context, params ConversationListParams, opts ...option.RequestOption) (res *APIResponseOfConversationMessagesList, err error) {
53+
func (r *ConversationService) List(ctx context.Context, params ConversationListParams, opts ...option.RequestOption) (res *pagination.ConversationsPage[ConversationMessagesListMessage], err error) {
54+
var raw *http.Response
5355
if !param.IsOmitted(params.XProfileID) {
5456
opts = append(opts, option.WithHeader("x-profile-id", fmt.Sprintf("%v", params.XProfileID.Value)))
5557
}
5658
opts = slices.Concat(r.Options, opts)
59+
opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
5760
path := "v3/conversations"
58-
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, params, &res, opts...)
59-
return res, err
61+
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
62+
if err != nil {
63+
return nil, err
64+
}
65+
err = cfg.Execute()
66+
if err != nil {
67+
return nil, err
68+
}
69+
res.SetPageConfig(cfg, raw)
70+
return res, nil
71+
}
72+
73+
// Retrieves a paginated list of the authenticated customer's messages across all
74+
// conversations, ordered by created date (most recent first).
75+
func (r *ConversationService) ListAutoPaging(ctx context.Context, params ConversationListParams, opts ...option.RequestOption) *pagination.ConversationsPageAutoPager[ConversationMessagesListMessage] {
76+
return pagination.NewConversationsPageAutoPager(r.List(ctx, params, opts...))
6077
}
6178

6279
// Retrieves a paginated list of the messages in a single conversation (scoped to
6380
// the authenticated customer), ordered by created date (most recent first).
64-
func (r *ConversationService) ListMessages(ctx context.Context, id string, params ConversationListMessagesParams, opts ...option.RequestOption) (res *APIResponseOfConversationMessagesList, err error) {
81+
func (r *ConversationService) ListMessages(ctx context.Context, id string, params ConversationListMessagesParams, opts ...option.RequestOption) (res *pagination.ConversationsPage[ConversationMessagesListMessage], err error) {
82+
var raw *http.Response
6583
if !param.IsOmitted(params.XProfileID) {
6684
opts = append(opts, option.WithHeader("x-profile-id", fmt.Sprintf("%v", params.XProfileID.Value)))
6785
}
6886
opts = slices.Concat(r.Options, opts)
87+
opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
6988
if id == "" {
7089
err = errors.New("missing required id parameter")
7190
return nil, err
7291
}
7392
path := fmt.Sprintf("v3/conversations/%s", id)
74-
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, params, &res, opts...)
75-
return res, err
93+
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
94+
if err != nil {
95+
return nil, err
96+
}
97+
err = cfg.Execute()
98+
if err != nil {
99+
return nil, err
100+
}
101+
res.SetPageConfig(cfg, raw)
102+
return res, nil
103+
}
104+
105+
// Retrieves a paginated list of the messages in a single conversation (scoped to
106+
// the authenticated customer), ordered by created date (most recent first).
107+
func (r *ConversationService) ListMessagesAutoPaging(ctx context.Context, id string, params ConversationListMessagesParams, opts ...option.RequestOption) *pagination.ConversationsPageAutoPager[ConversationMessagesListMessage] {
108+
return pagination.NewConversationsPageAutoPager(r.ListMessages(ctx, id, params, opts...))
76109
}
77110

78111
// Standard API response envelope for all v3 endpoints
@@ -242,8 +275,8 @@ func (r *ConversationMessagesListMessageMessageBodyButton) UnmarshalJSON(data []
242275
}
243276

244277
type ConversationListParams struct {
245-
Page int64 `query:"page" api:"required" json:"-"`
246-
PageSize int64 `query:"page_size" api:"required" json:"-"`
278+
Page param.Opt[int64] `query:"page,omitzero" json:"-"`
279+
PageSize param.Opt[int64] `query:"page_size,omitzero" json:"-"`
247280
XProfileID param.Opt[string] `header:"x-profile-id,omitzero" format:"uuid" json:"-"`
248281
paramObj
249282
}
@@ -257,8 +290,8 @@ func (r ConversationListParams) URLQuery() (v url.Values, err error) {
257290
}
258291

259292
type ConversationListMessagesParams struct {
260-
Page int64 `query:"page" api:"required" json:"-"`
261-
PageSize int64 `query:"page_size" api:"required" json:"-"`
293+
Page param.Opt[int64] `query:"page,omitzero" json:"-"`
294+
PageSize param.Opt[int64] `query:"page_size,omitzero" json:"-"`
262295
XProfileID param.Opt[string] `header:"x-profile-id,omitzero" format:"uuid" json:"-"`
263296
paramObj
264297
}

‎conversation_test.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func TestConversationListWithOptionalParams(t *testing.T) {
2727
option.WithAPIKey("My API Key"),
2828
)
2929
_, err := client.Conversations.List(context.TODO(), sentdm.ConversationListParams{
30-
Page: 0,
31-
PageSize: 0,
30+
Page: sentdm.Int(0),
31+
PageSize: sentdm.Int(0),
3232
XProfileID: sentdm.String("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"),
3333
})
3434
if err != nil {
@@ -57,8 +57,8 @@ func TestConversationListMessagesWithOptionalParams(t *testing.T) {
5757
context.TODO(),
5858
"08fab313-c9e2-502c-975e-08b0356c432e",
5959
sentdm.ConversationListMessagesParams{
60-
Page: 0,
61-
PageSize: 0,
60+
Page: sentdm.Int(0),
61+
PageSize: sentdm.Int(0),
6262
XProfileID: sentdm.String("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"),
6363
},
6464
)

0 commit comments

Comments
 (0)