Skip to content

Commit 992357b

Browse files
Merge pull request #89 from kaleido-io/always-paginate
config for always returning pagination response
2 parents 33b402c + 2ee925a commit 992357b

File tree

6 files changed

+66
-16
lines changed

6 files changed

+66
-16
lines changed

pkg/ffapi/apirequest.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2023 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -31,17 +31,24 @@ type APIRequest struct {
3131
Part *Multipart
3232
SuccessStatus int
3333
ResponseHeaders http.Header
34+
AlwaysPaginate bool
3435
}
3536

3637
// FilterResult is a helper to transform a filter result into a REST API standard payload
3738
func (r *APIRequest) FilterResult(items interface{}, res *FilterResult, err error) (interface{}, error) {
3839
itemsVal := reflect.ValueOf(items)
39-
if err != nil || res == nil || res.TotalCount == nil || itemsVal.Kind() != reflect.Slice {
40-
return items, err
40+
if itemsVal.Kind() == reflect.Slice && (r.AlwaysPaginate || (res != nil && res.TotalCount != nil)) {
41+
response := &FilterResultsWithCount{
42+
Items: items,
43+
}
44+
if res != nil {
45+
response.Total = res.TotalCount
46+
}
47+
if itemsVal.Kind() == reflect.Slice {
48+
response.Count = int64(itemsVal.Len())
49+
}
50+
return response, err
4151
}
42-
return &FilterResultsWithCount{
43-
Total: *res.TotalCount,
44-
Count: int64(itemsVal.Len()),
45-
Items: items,
46-
}, nil
52+
return items, err
53+
4754
}

pkg/ffapi/apirequest_test.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestFilterResultWithCount(t *testing.T) {
3131
assert.NoError(t, err)
3232
assert.Equal(t, &FilterResultsWithCount{
3333
Count: 1,
34-
Total: 10,
34+
Total: &ten,
3535
Items: []string{"test"},
3636
}, f)
3737
}
@@ -42,3 +42,36 @@ func TestFilterResultPlain(t *testing.T) {
4242
assert.NoError(t, err)
4343
assert.Equal(t, []string{"test"}, f)
4444
}
45+
46+
func TestFilterResultWithCountNoTotal(t *testing.T) {
47+
r := &APIRequest{
48+
AlwaysPaginate: true,
49+
}
50+
f, err := r.FilterResult([]string{"test"}, &FilterResult{}, nil)
51+
assert.NoError(t, err)
52+
assert.Equal(t, &FilterResultsWithCount{
53+
Count: 1,
54+
Items: []string{"test"},
55+
}, f)
56+
}
57+
58+
func TestFilterResultAlwyasPaginateNoSlice(t *testing.T) {
59+
r := &APIRequest{
60+
AlwaysPaginate: true,
61+
}
62+
f, err := r.FilterResult("test", &FilterResult{}, nil)
63+
assert.NoError(t, err)
64+
assert.Equal(t, "test", f)
65+
}
66+
67+
func TestFilterResultAlwaysPaginateNoFilterResult(t *testing.T) {
68+
r := &APIRequest{
69+
AlwaysPaginate: true,
70+
}
71+
f, err := r.FilterResult([]string{"test"}, nil, nil)
72+
assert.NoError(t, err)
73+
assert.Equal(t, &FilterResultsWithCount{
74+
Count: 1,
75+
Items: []string{"test"},
76+
}, f)
77+
}

pkg/ffapi/apiserver.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type apiServer[T any] struct {
5959
requestTimeout time.Duration
6060
requestMaxTimeout time.Duration
6161
apiPublicURL string
62+
alwaysPaginate bool
6263
metricsEnabled bool
6364
metricsPath string
6465
metricsPublicURL string
@@ -89,12 +90,16 @@ type APIServerRouteExt[T any] struct {
8990
// the supplied wrapper function - which will inject
9091
func NewAPIServer[T any](ctx context.Context, options APIServerOptions[T]) APIServer {
9192
as := &apiServer[T]{
92-
requestTimeout: options.APIConfig.GetDuration(ConfAPIRequestTimeout),
93-
requestMaxTimeout: options.APIConfig.GetDuration(ConfAPIRequestMaxTimeout),
94-
metricsEnabled: options.MetricsConfig.GetBool(ConfMetricsServerEnabled),
95-
metricsPath: options.MetricsConfig.GetString(ConfMetricsServerPath),
96-
APIServerOptions: options,
97-
started: make(chan struct{}),
93+
defaultFilterLimit: options.APIConfig.GetUint64(ConfAPIDefaultFilterLimit),
94+
maxFilterLimit: options.APIConfig.GetUint64(ConfAPIMaxFilterLimit),
95+
maxFilterSkip: options.APIConfig.GetUint64(ConfAPIMaxFilterSkip),
96+
requestTimeout: options.APIConfig.GetDuration(ConfAPIRequestTimeout),
97+
requestMaxTimeout: options.APIConfig.GetDuration(ConfAPIRequestMaxTimeout),
98+
metricsEnabled: options.MetricsConfig.GetBool(ConfMetricsServerEnabled),
99+
metricsPath: options.MetricsConfig.GetString(ConfMetricsServerPath),
100+
alwaysPaginate: options.APIConfig.GetBool(ConfAPIAlwaysPaginate),
101+
APIServerOptions: options,
102+
started: make(chan struct{}),
98103
}
99104
if as.FavIcon16 == nil {
100105
as.FavIcon16 = ffLogo16
@@ -239,6 +244,7 @@ func (as *apiServer[T]) handlerFactory() *HandlerFactory {
239244
MaxFilterSkip: as.maxFilterSkip,
240245
MaxFilterLimit: as.maxFilterLimit,
241246
SupportFieldRedaction: as.SupportFieldRedaction,
247+
AlwaysPaginate: as.alwaysPaginate,
242248
}
243249
}
244250

pkg/ffapi/apiserver_config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ var (
3030
ConfAPIMaxFilterSkip = "maxFilterSkip"
3131
ConfAPIRequestTimeout = "requestTimeout"
3232
ConfAPIRequestMaxTimeout = "requestMaxTimeout"
33+
ConfAPIAlwaysPaginate = "alwaysPaginate"
3334
)
3435

3536
func InitAPIServerConfig(apiConfig, metricsConfig, corsConfig config.Section) {
@@ -39,6 +40,7 @@ func InitAPIServerConfig(apiConfig, metricsConfig, corsConfig config.Section) {
3940
apiConfig.AddKnownKey(ConfAPIMaxFilterSkip, 100000)
4041
apiConfig.AddKnownKey(ConfAPIRequestTimeout, "30s")
4142
apiConfig.AddKnownKey(ConfAPIRequestMaxTimeout, "10m")
43+
apiConfig.AddKnownKey(ConfAPIAlwaysPaginate, false)
4244

4345
httpserver.InitCORSConfig(corsConfig)
4446

pkg/ffapi/handler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type HandlerFactory struct {
4848
MaxFilterSkip uint64
4949
MaxFilterLimit uint64
5050
PassthroughHeaders []string
51+
AlwaysPaginate bool
5152
SupportFieldRedaction bool
5253
}
5354

@@ -172,6 +173,7 @@ func (hs *HandlerFactory) RouteHandler(route *Route) http.HandlerFunc {
172173
Input: jsonInput,
173174
SuccessStatus: http.StatusOK,
174175
ResponseHeaders: res.Header(),
176+
AlwaysPaginate: hs.AlwaysPaginate,
175177
}
176178
if len(route.JSONOutputCodes) > 0 {
177179
r.SuccessStatus = route.JSONOutputCodes[0]

pkg/ffapi/restfilter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
type FilterResultsWithCount struct {
3333
Count int64 `json:"count"`
34-
Total int64 `json:"total"`
34+
Total *int64 `json:"total,omitempty"` // omitted if a count was not calculated (AlwaysPaginate enabled, and count not specified)
3535
Items interface{} `json:"items"`
3636
}
3737

0 commit comments

Comments
 (0)