Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
38bbc097
Commit
38bbc097
authored
Feb 15, 2019
by
Adam Mulvany
Committed by
Rémy Coutable
Feb 21, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Properly implement API pagination headers and add specs
Signed-off-by:
Rémy Coutable
<
remy@rymai.me
>
parent
cf8c2eeb
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
109 additions
and
154 deletions
+109
-154
lib/api/helpers/pagination.rb
lib/api/helpers/pagination.rb
+36
-39
spec/lib/api/helpers/pagination_spec.rb
spec/lib/api/helpers/pagination_spec.rb
+64
-91
spec/lib/gitlab/serializer/pagination_spec.rb
spec/lib/gitlab/serializer/pagination_spec.rb
+3
-7
spec/serializers/environment_serializer_spec.rb
spec/serializers/environment_serializer_spec.rb
+2
-7
spec/serializers/pipeline_serializer_spec.rb
spec/serializers/pipeline_serializer_spec.rb
+4
-10
No files found.
lib/api/helpers/pagination.rb
View file @
38bbc097
...
@@ -13,6 +13,33 @@ module API
...
@@ -13,6 +13,33 @@ module API
strategy
.
new
(
self
).
paginate
(
relation
)
strategy
.
new
(
self
).
paginate
(
relation
)
end
end
class
Base
private
def
per_page
@per_page
||=
params
[
:per_page
]
end
def
base_request_uri
@base_request_uri
||=
URI
.
parse
(
request
.
url
).
tap
do
|
uri
|
uri
.
host
=
Gitlab
.
config
.
gitlab
.
host
uri
.
port
=
nil
end
end
def
build_page_url
(
query_params
:)
base_request_uri
.
tap
do
|
uri
|
uri
.
query
=
query_params
end
.
to_s
end
def
page_href
(
next_page_params
=
{})
query_params
=
params
.
merge
(
**
next_page_params
,
per_page:
per_page
).
to_query
build_page_url
(
query_params:
query_params
)
end
end
class
KeysetPaginationInfo
class
KeysetPaginationInfo
attr_reader
:relation
,
:request_context
attr_reader
:relation
,
:request_context
...
@@ -85,7 +112,7 @@ module API
...
@@ -85,7 +112,7 @@ module API
end
end
end
end
class
KeysetPaginationStrategy
class
KeysetPaginationStrategy
<
Base
attr_reader
:request_context
attr_reader
:request_context
delegate
:params
,
:header
,
:request
,
to: :request_context
delegate
:params
,
:header
,
:request
,
to: :request_context
...
@@ -141,10 +168,6 @@ module API
...
@@ -141,10 +168,6 @@ module API
]
]
end
end
def
per_page
params
[
:per_page
]
end
def
add_default_pagination_headers
def
add_default_pagination_headers
header
'X-Per-Page'
,
per_page
.
to_s
header
'X-Per-Page'
,
per_page
.
to_s
end
end
...
@@ -154,22 +177,12 @@ module API
...
@@ -154,22 +177,12 @@ module API
header
'Link'
,
link_for
(
'next'
,
next_page_params
)
header
'Link'
,
link_for
(
'next'
,
next_page_params
)
end
end
def
page_href
(
next_page_params
)
request_url
=
request
.
url
.
split
(
'?'
).
first
request_params
=
params
.
dup
request_params
[
:per_page
]
=
per_page
request_params
.
merge!
(
next_page_params
)
if
next_page_params
"
#{
request_url
}
?
#{
request_params
.
to_query
}
"
end
def
link_for
(
rel
,
next_page_params
)
def
link_for
(
rel
,
next_page_params
)
%(<#{page_href(next_page_params)}>; rel="#{rel}")
%(<#{page_href(next_page_params)}>; rel="#{rel}")
end
end
end
end
class
DefaultPaginationStrategy
class
DefaultPaginationStrategy
<
Base
attr_reader
:request_context
attr_reader
:request_context
delegate
:params
,
:header
,
:request
,
to: :request_context
delegate
:params
,
:header
,
:request
,
to: :request_context
...
@@ -198,15 +211,13 @@ module API
...
@@ -198,15 +211,13 @@ module API
end
end
end
end
# rubocop: disable CodeReuse/ActiveRecord
def
add_default_order
(
relation
)
def
add_default_order
(
relation
)
if
relation
.
is_a?
(
ActiveRecord
::
Relation
)
&&
relation
.
order_values
.
empty?
if
relation
.
is_a?
(
ActiveRecord
::
Relation
)
&&
relation
.
order_values
.
empty?
relation
=
relation
.
order
(
:id
)
relation
=
relation
.
order
(
:id
)
# rubocop: disable CodeReuse/ActiveRecord
end
end
relation
relation
end
end
# rubocop: enable CodeReuse/ActiveRecord
def
add_pagination_headers
(
paginated_data
)
def
add_pagination_headers
(
paginated_data
)
header
'X-Per-Page'
,
paginated_data
.
limit_value
.
to_s
header
'X-Per-Page'
,
paginated_data
.
limit_value
.
to_s
...
@@ -222,27 +233,13 @@ module API
...
@@ -222,27 +233,13 @@ module API
end
end
def
pagination_links
(
paginated_data
)
def
pagination_links
(
paginated_data
)
request_url
=
request
.
url
.
split
(
'?'
).
first
[].
tap
do
|
links
|
request_params
=
params
.
clone
links
<<
%(<#{page_href(page: paginated_data.prev_page)}>; rel="prev")
if
paginated_data
.
prev_page
request_params
[
:per_page
]
=
paginated_data
.
limit_value
links
<<
%(<#{page_href(page: paginated_data.next_page)}>; rel="next")
if
paginated_data
.
next_page
links
<<
%(<#{page_href(page: 1)}>; rel="first")
links
=
[]
request_params
[
:page
]
=
paginated_data
.
prev_page
links
<<
%(<#{request_url}?#{request_params.to_query}>; rel="prev")
if
request_params
[
:page
]
request_params
[
:page
]
=
paginated_data
.
next_page
links
<<
%(<#{request_url}?#{request_params.to_query}>; rel="next")
if
request_params
[
:page
]
request_params
[
:page
]
=
1
links
<<
%(<#{request_url}?#{request_params.to_query}>; rel="first")
unless
data_without_counts?
(
paginated_data
)
request_params
[
:page
]
=
total_pages
(
paginated_data
)
links
<<
%(<#{request_url}?#{request_params.to_query}>; rel="last")
end
links
.
join
(
', '
)
links
<<
%(<#{page_href(page: total_pages(paginated_data))}>; rel="last")
unless
data_without_counts?
(
paginated_data
)
end
.
join
(
', '
)
end
end
def
total_pages
(
paginated_data
)
def
total_pages
(
paginated_data
)
...
...
spec/lib/api/helpers/pagination_spec.rb
View file @
38bbc097
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/serializer/pagination_spec.rb
View file @
38bbc097
require
'spec_helper'
require
'spec_helper'
describe
Gitlab
::
Serializer
::
Pagination
do
describe
Gitlab
::
Serializer
::
Pagination
do
let
(
:request
)
{
spy
(
'request'
)
}
let
(
:request
)
{
double
(
url:
"
#{
Gitlab
.
config
.
gitlab
.
url
}
:8080/api/v4/projects?
#{
query
.
to_query
}
"
,
query_parameters:
query
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:headers
)
{
spy
(
'headers'
)
}
let
(
:headers
)
{
spy
(
'headers'
)
}
before
do
before
do
allow
(
request
).
to
receive
(
:query_parameters
)
allow
(
response
).
to
receive
(
:headers
).
and_return
(
headers
)
.
and_return
(
params
)
allow
(
response
).
to
receive
(
:headers
)
.
and_return
(
headers
)
end
end
let
(
:pagination
)
{
described_class
.
new
(
request
,
response
)
}
let
(
:pagination
)
{
described_class
.
new
(
request
,
response
)
}
...
@@ -19,7 +15,7 @@ describe Gitlab::Serializer::Pagination do
...
@@ -19,7 +15,7 @@ describe Gitlab::Serializer::Pagination do
subject
{
pagination
.
paginate
(
resource
)
}
subject
{
pagination
.
paginate
(
resource
)
}
let
(
:resource
)
{
User
.
all
}
let
(
:resource
)
{
User
.
all
}
let
(
:
params
)
{
{
page:
1
,
per_page:
2
}
}
let
(
:
query
)
{
{
page:
1
,
per_page:
2
}
}
context
'when a multiple resources are present in relation'
do
context
'when a multiple resources are present in relation'
do
before
do
before
do
...
...
spec/serializers/environment_serializer_spec.rb
View file @
38bbc097
...
@@ -124,10 +124,10 @@ describe EnvironmentSerializer do
...
@@ -124,10 +124,10 @@ describe EnvironmentSerializer do
end
end
context
'when used with pagination'
do
context
'when used with pagination'
do
let
(
:request
)
{
spy
(
'request'
)
}
let
(
:request
)
{
double
(
url:
"
#{
Gitlab
.
config
.
gitlab
.
url
}
:8080/api/v4/projects?
#{
query
.
to_query
}
"
,
query_parameters:
query
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:resource
)
{
Environment
.
all
}
let
(
:resource
)
{
Environment
.
all
}
let
(
:
pagination
)
{
{
page:
1
,
per_page:
2
}
}
let
(
:
query
)
{
{
page:
1
,
per_page:
2
}
}
let
(
:serializer
)
do
let
(
:serializer
)
do
described_class
described_class
...
@@ -135,11 +135,6 @@ describe EnvironmentSerializer do
...
@@ -135,11 +135,6 @@ describe EnvironmentSerializer do
.
with_pagination
(
request
,
response
)
.
with_pagination
(
request
,
response
)
end
end
before
do
allow
(
request
).
to
receive
(
:query_parameters
)
.
and_return
(
pagination
)
end
subject
{
serializer
.
represent
(
resource
)
}
subject
{
serializer
.
represent
(
resource
)
}
it
'creates a paginated serializer'
do
it
'creates a paginated serializer'
do
...
...
spec/serializers/pipeline_serializer_spec.rb
View file @
38bbc097
...
@@ -38,15 +38,9 @@ describe PipelineSerializer do
...
@@ -38,15 +38,9 @@ describe PipelineSerializer do
end
end
context
'when used with pagination'
do
context
'when used with pagination'
do
let
(
:request
)
{
spy
(
'request'
)
}
let
(
:request
)
{
double
(
url:
"
#{
Gitlab
.
config
.
gitlab
.
url
}
:8080/api/v4/projects?
#{
query
.
to_query
}
"
,
query_parameters:
query
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:response
)
{
spy
(
'response'
)
}
let
(
:pagination
)
{
{}
}
let
(
:query
)
{
{}
}
before
do
allow
(
request
)
.
to
receive
(
:query_parameters
)
.
and_return
(
pagination
)
end
let
(
:serializer
)
do
let
(
:serializer
)
do
described_class
.
new
(
current_user:
user
)
described_class
.
new
(
current_user:
user
)
...
@@ -60,7 +54,7 @@ describe PipelineSerializer do
...
@@ -60,7 +54,7 @@ describe PipelineSerializer do
context
'when resource is not paginatable'
do
context
'when resource is not paginatable'
do
context
'when a single pipeline object is being serialized'
do
context
'when a single pipeline object is being serialized'
do
let
(
:resource
)
{
create
(
:ci_empty_pipeline
)
}
let
(
:resource
)
{
create
(
:ci_empty_pipeline
)
}
let
(
:
pagination
)
{
{
page:
1
,
per_page:
1
}
}
let
(
:
query
)
{
{
page:
1
,
per_page:
1
}
}
it
'raises error'
do
it
'raises error'
do
expect
{
subject
}.
to
raise_error
(
expect
{
subject
}.
to
raise_error
(
...
@@ -71,7 +65,7 @@ describe PipelineSerializer do
...
@@ -71,7 +65,7 @@ describe PipelineSerializer do
context
'when resource is paginatable relation'
do
context
'when resource is paginatable relation'
do
let
(
:resource
)
{
Ci
::
Pipeline
.
all
}
let
(
:resource
)
{
Ci
::
Pipeline
.
all
}
let
(
:
pagination
)
{
{
page:
1
,
per_page:
2
}
}
let
(
:
query
)
{
{
page:
1
,
per_page:
2
}
}
context
'when a single pipeline object is present in relation'
do
context
'when a single pipeline object is present in relation'
do
before
do
before
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment