Skip to content

Commit 42729b7

Browse files
authored
fix API link header (#7298)
1 parent 5908bb1 commit 42729b7

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

modules/context/api.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package context
77

88
import (
99
"fmt"
10+
"net/url"
1011
"strings"
1112

1213
"github.com/go-macaron/csrf"
@@ -77,23 +78,49 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) {
7778
})
7879
}
7980

80-
// SetLinkHeader sets pagination link header by given total number and page size.
81-
func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
82-
page := NewPagination(total, pageSize, ctx.QueryInt("page"), 0)
81+
func genAPILinks(curURL *url.URL, total, pageSize, curPage int) []string {
82+
page := NewPagination(total, pageSize, curPage, 0)
8383
paginater := page.Paginater
8484
links := make([]string, 0, 4)
85+
8586
if paginater.HasNext() {
86-
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"next\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.Next()))
87+
u := *curURL
88+
queries := u.Query()
89+
queries.Set("page", fmt.Sprintf("%d", paginater.Next()))
90+
u.RawQuery = queries.Encode()
91+
92+
links = append(links, fmt.Sprintf("<%s%s>; rel=\"next\"", setting.AppURL, u.RequestURI()[1:]))
8793
}
8894
if !paginater.IsLast() {
89-
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"last\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.TotalPages()))
95+
u := *curURL
96+
queries := u.Query()
97+
queries.Set("page", fmt.Sprintf("%d", paginater.TotalPages()))
98+
u.RawQuery = queries.Encode()
99+
100+
links = append(links, fmt.Sprintf("<%s%s>; rel=\"last\"", setting.AppURL, u.RequestURI()[1:]))
90101
}
91102
if !paginater.IsFirst() {
92-
links = append(links, fmt.Sprintf("<%s%s?page=1>; rel=\"first\"", setting.AppURL, ctx.Req.URL.Path[1:]))
103+
u := *curURL
104+
queries := u.Query()
105+
queries.Set("page", "1")
106+
u.RawQuery = queries.Encode()
107+
108+
links = append(links, fmt.Sprintf("<%s%s>; rel=\"first\"", setting.AppURL, u.RequestURI()[1:]))
93109
}
94110
if paginater.HasPrevious() {
95-
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"prev\"", setting.AppURL, ctx.Req.URL.Path[1:], paginater.Previous()))
111+
u := *curURL
112+
queries := u.Query()
113+
queries.Set("page", fmt.Sprintf("%d", paginater.Previous()))
114+
u.RawQuery = queries.Encode()
115+
116+
links = append(links, fmt.Sprintf("<%s%s>; rel=\"prev\"", setting.AppURL, u.RequestURI()[1:]))
96117
}
118+
return links
119+
}
120+
121+
// SetLinkHeader sets pagination link header by given total number and page size.
122+
func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
123+
links := genAPILinks(ctx.Req.URL, total, pageSize, ctx.QueryInt("page"))
97124

98125
if len(links) > 0 {
99126
ctx.Header().Set("Link", strings.Join(links, ","))

modules/context/api_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package context
6+
7+
import (
8+
"net/url"
9+
"strconv"
10+
"testing"
11+
12+
"code.gitea.io/gitea/modules/setting"
13+
14+
"github.com/stretchr/testify/assert"
15+
)
16+
17+
func TestGenAPILinks(t *testing.T) {
18+
setting.AppURL = "http://localhost:3000/"
19+
var kases = map[string][]string{
20+
"api/v1/repos/jerrykan/example-repo/issues?state=all": {
21+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
22+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
23+
},
24+
"api/v1/repos/jerrykan/example-repo/issues?state=all&page=1": {
25+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=2&state=all>; rel="next"`,
26+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
27+
},
28+
"api/v1/repos/jerrykan/example-repo/issues?state=all&page=2": {
29+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=3&state=all>; rel="next"`,
30+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=5&state=all>; rel="last"`,
31+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
32+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="prev"`,
33+
},
34+
"api/v1/repos/jerrykan/example-repo/issues?state=all&page=5": {
35+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=1&state=all>; rel="first"`,
36+
`<http://localhost:3000/api/v1/repos/jerrykan/example-repo/issues?page=4&state=all>; rel="prev"`,
37+
},
38+
}
39+
40+
for req, response := range kases {
41+
u, err := url.Parse(setting.AppURL + req)
42+
assert.NoError(t, err)
43+
44+
p := u.Query().Get("page")
45+
curPage, _ := strconv.Atoi(p)
46+
47+
links := genAPILinks(u, 100, 20, curPage)
48+
49+
assert.EqualValues(t, links, response)
50+
}
51+
}

0 commit comments

Comments
 (0)