diff --git a/pagination/header.go b/pagination/header.go index 5b04a08a..eeb2a8b0 100644 --- a/pagination/header.go +++ b/pagination/header.go @@ -20,8 +20,10 @@ func header(u *url.URL, rel string, limit, offset int64) string { return fmt.Sprintf("<%s>; rel=\"%s\"", u.String(), rel) } +type formatter func(location *url.URL, rel string, itemsPerPage int64, offset int64) string + // HeaderWithFormatter adds an HTTP header for pagination which uses a custom formatter for generating the URL links. -func HeaderWithFormatter(w http.ResponseWriter, u *url.URL, total int64, page, itemsPerPage int, formatter func(*url.URL, string, int64, int64) string) { +func HeaderWithFormatter(w http.ResponseWriter, u *url.URL, total int64, page, itemsPerPage int, f formatter) { if itemsPerPage <= 0 { itemsPerPage = 1 } @@ -44,38 +46,38 @@ func HeaderWithFormatter(w http.ResponseWriter, u *url.URL, total int64, page, i if offset >= lastOffset { if total == 0 { w.Header().Set("Link", strings.Join([]string{ - formatter(u, "first", itemsPerPage64, 0), - formatter(u, "next", itemsPerPage64, ((offset/itemsPerPage64)+1)*itemsPerPage64), - formatter(u, "prev", itemsPerPage64, ((offset/itemsPerPage64)-1)*itemsPerPage64), + f(u, "first", itemsPerPage64, 0), + f(u, "next", itemsPerPage64, ((offset/itemsPerPage64)+1)*itemsPerPage64), + f(u, "prev", itemsPerPage64, ((offset/itemsPerPage64)-1)*itemsPerPage64), }, ",")) return } if total <= itemsPerPage64 { - w.Header().Set("link", formatter(u, "first", total, 0)) + w.Header().Set("link", f(u, "first", total, 0)) return } w.Header().Set("Link", strings.Join([]string{ - formatter(u, "first", itemsPerPage64, 0), - formatter(u, "prev", itemsPerPage64, lastOffset-itemsPerPage64), + f(u, "first", itemsPerPage64, 0), + f(u, "prev", itemsPerPage64, lastOffset-itemsPerPage64), }, ",")) return } if offset < itemsPerPage64 { w.Header().Set("Link", strings.Join([]string{ - formatter(u, "next", itemsPerPage64, itemsPerPage64), - formatter(u, "last", itemsPerPage64, lastOffset), + f(u, "next", itemsPerPage64, itemsPerPage64), + f(u, "last", itemsPerPage64, lastOffset), }, ",")) return } w.Header().Set("Link", strings.Join([]string{ - formatter(u, "first", itemsPerPage64, 0), - formatter(u, "next", itemsPerPage64, ((offset/itemsPerPage64)+1)*itemsPerPage64), - formatter(u, "prev", itemsPerPage64, ((offset/itemsPerPage64)-1)*itemsPerPage64), - formatter(u, "last", itemsPerPage64, lastOffset), + f(u, "first", itemsPerPage64, 0), + f(u, "next", itemsPerPage64, ((offset/itemsPerPage64)+1)*itemsPerPage64), + f(u, "prev", itemsPerPage64, ((offset/itemsPerPage64)-1)*itemsPerPage64), + f(u, "last", itemsPerPage64, lastOffset), }, ",")) } diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json index 95f4dc06..6edb5858 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json @@ -1,5 +1,5 @@ [ - "\u003chttp://example.com?page=1\u0026page_size=50\u0026page_token=eyJwYWdlIjoiNTAiLCJ2IjoxfQ\u0026per_page=50\u003e", - "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u0026per_page=50\u003e", + "\u003chttp://example.com?page=1\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiI1MCIsInYiOjJ9\u0026per_page=50\u003e", + "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u0026per_page=50\u003e", "rel=\"last\"" ] diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json index 16269d27..e8b62892 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json @@ -1,4 +1,4 @@ [ - "\u003chttp://example.com?page=0\u0026page_size=5\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u0026per_page=5\u003e", + "\u003chttp://example.com?page=0\u0026page_size=5\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u0026per_page=5\u003e", "rel=\"first\"" ] diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json index 4997ef24..62b14573 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json @@ -1,7 +1,7 @@ [ - "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u0026per_page=50\u003e", - "rel=\"first\",\u003chttp://example.com?page=4\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMjAwIiwidiI6MX0\u0026per_page=50\u003e", - "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u0026per_page=50\u003e", - "rel=\"prev\",\u003chttp://example.com?page=5\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMjUwIiwidiI6MX0\u0026per_page=50\u003e", + "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u0026per_page=50\u003e", + "rel=\"first\",\u003chttp://example.com?page=4\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIyMDAiLCJ2IjoyfQ\u0026per_page=50\u003e", + "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u0026per_page=50\u003e", + "rel=\"prev\",\u003chttp://example.com?page=5\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIyNTAiLCJ2IjoyfQ\u0026per_page=50\u003e", "rel=\"last\"" ] diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json index 1cc5e4bc..c8797e2b 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json @@ -1,6 +1,6 @@ [ - "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u0026per_page=50\u003e", - "rel=\"first\",\u003chttp://example.com?page=4\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMjAwIiwidiI6MX0\u0026per_page=50\u003e", - "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u0026per_page=50\u003e", + "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u0026per_page=50\u003e", + "rel=\"first\",\u003chttp://example.com?page=4\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIyMDAiLCJ2IjoyfQ\u0026per_page=50\u003e", + "rel=\"next\",\u003chttp://example.com?page=2\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u0026per_page=50\u003e", "rel=\"prev\"" ] diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json index fcb0fdb9..d7f30929 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json @@ -1,5 +1,5 @@ [ - "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u0026per_page=50\u003e", - "rel=\"first\",\u003chttp://example.com?page=1\u0026page_size=50\u0026page_token=eyJwYWdlIjoiNTAiLCJ2IjoxfQ\u0026per_page=50\u003e", + "\u003chttp://example.com?page=0\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u0026per_page=50\u003e", + "rel=\"first\",\u003chttp://example.com?page=1\u0026page_size=50\u0026page_token=eyJvZmZzZXQiOiI1MCIsInYiOjJ9\u0026per_page=50\u003e", "rel=\"prev\"" ] diff --git a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json index 54902556..bf1395cc 100644 --- a/pagination/migrationpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json +++ b/pagination/migrationpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json @@ -1,7 +1,7 @@ [ - "\u003chttp://example.com?page=0\u0026page_size=1\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u0026per_page=1\u003e", - "rel=\"first\",\u003chttp://example.com?page=21\u0026page_size=1\u0026page_token=eyJwYWdlIjoiMjEiLCJ2IjoxfQ\u0026per_page=1\u003e", - "rel=\"next\",\u003chttp://example.com?page=19\u0026page_size=1\u0026page_token=eyJwYWdlIjoiMTkiLCJ2IjoxfQ\u0026per_page=1\u003e", - "rel=\"prev\",\u003chttp://example.com?page=99\u0026page_size=1\u0026page_token=eyJwYWdlIjoiOTkiLCJ2IjoxfQ\u0026per_page=1\u003e", + "\u003chttp://example.com?page=0\u0026page_size=1\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u0026per_page=1\u003e", + "rel=\"first\",\u003chttp://example.com?page=21\u0026page_size=1\u0026page_token=eyJvZmZzZXQiOiIyMSIsInYiOjJ9\u0026per_page=1\u003e", + "rel=\"next\",\u003chttp://example.com?page=19\u0026page_size=1\u0026page_token=eyJvZmZzZXQiOiIxOSIsInYiOjJ9\u0026per_page=1\u003e", + "rel=\"prev\",\u003chttp://example.com?page=99\u0026page_size=1\u0026page_token=eyJvZmZzZXQiOiI5OSIsInYiOjJ9\u0026per_page=1\u003e", "rel=\"last\"" ] diff --git a/pagination/migrationpagination/pagination.go b/pagination/migrationpagination/pagination.go index 93079b16..38640150 100644 --- a/pagination/migrationpagination/pagination.go +++ b/pagination/migrationpagination/pagination.go @@ -33,12 +33,12 @@ func (p *Paginator) ParsePagination(r *http.Request) (page, itemsPerPage int) { return p.p.ParsePagination(r) } -func header(u *url.URL, rel string, itemsPerPage, page int64) string { +func header(u *url.URL, rel string, itemsPerPage, offset int64) string { q := u.Query() q.Set("page_size", fmt.Sprintf("%d", itemsPerPage)) - q.Set("page_token", tokenpagination.Encode(page)) + q.Set("page_token", tokenpagination.Encode(offset)) q.Set("per_page", fmt.Sprintf("%d", itemsPerPage)) - q.Set("page", fmt.Sprintf("%d", page/itemsPerPage)) + q.Set("page", fmt.Sprintf("%d", offset/itemsPerPage)) u.RawQuery = q.Encode() return fmt.Sprintf("<%s>; rel=\"%s\"", u.String(), rel) } diff --git a/pagination/migrationpagination/pagination_test.go b/pagination/migrationpagination/pagination_test.go index 5df70bee..d094ef6c 100644 --- a/pagination/migrationpagination/pagination_test.go +++ b/pagination/migrationpagination/pagination_test.go @@ -84,11 +84,11 @@ func TestParsePagination(t *testing.T) { expectedItemsPerPage int expectedPage int }{ - {"normal", "http://localhost/foo?page_size=10&page_token=eyJwYWdlIjoxMH0", 10, 10}, - {"normal-encoded", fmt.Sprintf("http://localhost/foo?page_size=10&page_token=%s", tokenpagination.Encode(10)), 10, 10}, + {"normal", "http://localhost/foo?page_size=10&page_token=eyJvZmZzZXQiOjEwfQ", 10, 1}, + {"normal-encoded", fmt.Sprintf("http://localhost/foo?page_size=10&page_token=%s", tokenpagination.Encode(10)), 10, 1}, {"defaults", "http://localhost/foo", 250, 0}, {"limits", "http://localhost/foo?page_size=2000", 1000, 0}, - {"negatives", "http://localhost/foo?page_size=-1&page=eyJwYWdlIjotMX0", 1, 0}, + {"negatives", "http://localhost/foo?page_size=-1&page=eyJvZmZzZXQiOi0xfQ", 1, 0}, {"negatives-encoded", fmt.Sprintf("http://localhost/foo?page_size=-1&page=%s", tokenpagination.Encode(-1)), 1, 0}, {"invalid_params", "http://localhost/foo?page_size=a&page=b", 250, 0}, {"legacy-normal", "http://localhost/foo?per_page=10&page=10", 10, 10}, diff --git a/pagination/pagepagination/pagination.go b/pagination/pagepagination/pagination.go index c667c7f2..915b7f45 100644 --- a/pagination/pagepagination/pagination.go +++ b/pagination/pagepagination/pagination.go @@ -66,10 +66,10 @@ func (p *PagePaginator) ParsePagination(r *http.Request) (page, itemsPerPage int return } -func header(u *url.URL, rel string, limit, page int64) string { +func header(u *url.URL, rel string, limit, offset int64) string { q := u.Query() q.Set("per_page", fmt.Sprintf("%d", limit)) - q.Set("page", fmt.Sprintf("%d", page/limit)) + q.Set("page", fmt.Sprintf("%d", offset/limit)) u.RawQuery = q.Encode() return fmt.Sprintf("<%s>; rel=\"%s\"", u.String(), rel) } diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json index 9c10df2c..2ef4cf13 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_next_and_last,_but_not_previous_or_first_if_at_the_beginning.json @@ -1,5 +1,5 @@ [ - "\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiNTAiLCJ2IjoxfQ\u003e", - "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u003e", + "\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiI1MCIsInYiOjJ9\u003e", + "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u003e", "rel=\"last\"" ] diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json index 3faa0c71..77b67838 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_only_first_if_the_limits_provided_exceeds_the_number_of_clients_found.json @@ -1,4 +1,4 @@ [ - "\u003chttp://example.com?page_size=5\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u003e", + "\u003chttp://example.com?page_size=5\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u003e", "rel=\"first\"" ] diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json index b4cb71a3..821898e1 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_and_last_if_in_the_middle.json @@ -1,7 +1,7 @@ [ - "\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u003e", - "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMjAwIiwidiI6MX0\u003e", - "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u003e", - "rel=\"prev\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMjUwIiwidiI6MX0\u003e", + "\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u003e", + "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIyMDAiLCJ2IjoyfQ\u003e", + "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u003e", + "rel=\"prev\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIyNTAiLCJ2IjoyfQ\u003e", "rel=\"last\"" ] diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json index ffc3a02d..c131e472 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous,_next,_first,_but_not_last_if_in_the_middle_and_no_total_was_provided.json @@ -1,6 +1,6 @@ [ - "\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u003e", - "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMjAwIiwidiI6MX0\u003e", - "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMTAwIiwidiI6MX0\u003e", + "\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u003e", + "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIyMDAiLCJ2IjoyfQ\u003e", + "rel=\"next\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIxMDAiLCJ2IjoyfQ\u003e", "rel=\"prev\"" ] diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json index ae8ffebb..1fb35d54 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Create_previous_and_first_but_not_next_or_last_if_at_the_end.json @@ -1,5 +1,5 @@ [ - "\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u003e", - "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJwYWdlIjoiNTAiLCJ2IjoxfQ\u003e", + "\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u003e", + "rel=\"first\",\u003chttp://example.com?page_size=50\u0026page_token=eyJvZmZzZXQiOiI1MCIsInYiOjJ9\u003e", "rel=\"prev\"" ] diff --git a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json index ff94bb5c..e5697f01 100644 --- a/pagination/tokenpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json +++ b/pagination/tokenpagination/.snapshots/TestPaginationHeader-Header_should_default_limit_to_1_no_limit_was_provided.json @@ -1,7 +1,7 @@ [ - "\u003chttp://example.com?page_size=1\u0026page_token=eyJwYWdlIjoiMCIsInYiOjF9\u003e", - "rel=\"first\",\u003chttp://example.com?page_size=1\u0026page_token=eyJwYWdlIjoiMjEiLCJ2IjoxfQ\u003e", - "rel=\"next\",\u003chttp://example.com?page_size=1\u0026page_token=eyJwYWdlIjoiMTkiLCJ2IjoxfQ\u003e", - "rel=\"prev\",\u003chttp://example.com?page_size=1\u0026page_token=eyJwYWdlIjoiOTkiLCJ2IjoxfQ\u003e", + "\u003chttp://example.com?page_size=1\u0026page_token=eyJvZmZzZXQiOiIwIiwidiI6Mn0\u003e", + "rel=\"first\",\u003chttp://example.com?page_size=1\u0026page_token=eyJvZmZzZXQiOiIyMSIsInYiOjJ9\u003e", + "rel=\"next\",\u003chttp://example.com?page_size=1\u0026page_token=eyJvZmZzZXQiOiIxOSIsInYiOjJ9\u003e", + "rel=\"prev\",\u003chttp://example.com?page_size=1\u0026page_token=eyJvZmZzZXQiOiI5OSIsInYiOjJ9\u003e", "rel=\"last\"" ] diff --git a/pagination/tokenpagination/pagination.go b/pagination/tokenpagination/pagination.go index 8795a576..53915786 100644 --- a/pagination/tokenpagination/pagination.go +++ b/pagination/tokenpagination/pagination.go @@ -19,7 +19,7 @@ import ( ) func Encode(offset int64) string { - return base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"page":"%d","v":1}`, offset))) + return base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf(`{"offset":"%d","v":2}`, offset))) } func decode(s string) (int, error) { @@ -28,7 +28,7 @@ func decode(s string) (int, error) { return 0, errors.WithStack(herodot.ErrBadRequest.WithWrap(err).WithReasonf("Unable to parse pagination token: %s", err)) } - return int(gjson.Get(string(b), "page").Int()), nil + return int(gjson.Get(string(b), "offset").Int()), nil } type TokenPaginator struct { @@ -50,8 +50,9 @@ func (p *TokenPaginator) defaults() { func (p *TokenPaginator) ParsePagination(r *http.Request) (page, itemsPerPage int) { p.defaults() + var offset int if offsetParam := r.URL.Query().Get("page_token"); len(offsetParam) > 0 { - page, _ = decode(offsetParam) + offset, _ = decode(offsetParam) } if gotLimit, err := strconv.ParseInt(r.URL.Query().Get("page_size"), 10, 0); err == nil { @@ -68,6 +69,10 @@ func (p *TokenPaginator) ParsePagination(r *http.Request) (page, itemsPerPage in itemsPerPage = 1 } + if offset > 0 { + page = offset / itemsPerPage + } + if page < 0 { page = 0 } @@ -75,10 +80,10 @@ func (p *TokenPaginator) ParsePagination(r *http.Request) (page, itemsPerPage in return } -func header(u *url.URL, rel string, itemsPerPage, page int64) string { +func header(u *url.URL, rel string, itemsPerPage, offset int64) string { q := u.Query() q.Set("page_size", fmt.Sprintf("%d", itemsPerPage)) - q.Set("page_token", Encode(page)) + q.Set("page_token", Encode(offset)) u.RawQuery = q.Encode() return fmt.Sprintf("<%s>; rel=\"%s\"", u.String(), rel) } diff --git a/pagination/tokenpagination/pagination_test.go b/pagination/tokenpagination/pagination_test.go index 22fadff9..55637371 100644 --- a/pagination/tokenpagination/pagination_test.go +++ b/pagination/tokenpagination/pagination_test.go @@ -81,11 +81,11 @@ func TestParsePagination(t *testing.T) { expectedItemsPerPage int expectedPage int }{ - {"normal", "http://localhost/foo?page_size=10&page_token=eyJwYWdlIjoxMH0", 10, 10}, - {"normal-encoded", "http://localhost/foo?page_size=10&page_token=" + Encode(10), 10, 10}, + {"normal", "http://localhost/foo?page_size=10&page_token=eyJvZmZzZXQiOjEwfQ", 10, 1}, + {"normal-encoded", "http://localhost/foo?page_size=10&page_token=" + Encode(10), 10, 1}, {"defaults", "http://localhost/foo", 250, 0}, {"limits", "http://localhost/foo?page_size=2000", 1000, 0}, - {"negatives", "http://localhost/foo?page_size=-1&page=eyJwYWdlIjotMX0", 1, 0}, + {"negatives", "http://localhost/foo?page_size=-1&page=eyJvZmZzZXQiOi0xfQ", 1, 0}, {"negatives-encoded", "http://localhost/foo?page_size=-1&page=" + Encode(-1), 1, 0}, {"invalid_params", "http://localhost/foo?page_size=a&page=b", 250, 0}, } {