Merge branch 'add-pagination-headers-to-api' into 'master'
Add pagination headers to already paginated API resources Following #3045, I've added pagination headers using already available Kaminari methods. ## Pagination headers in action ![Screen_Shot_2016-01-14_at_12.14.53](/uploads/88807f754dd9aafbb24da85f6bdf9521/Screen_Shot_2016-01-14_at_12.14.53.png) --- I've also added a shared example to test paginated API resources. A possible next step would be to paginate all the API resources that return an array. See merge request !2426
This commit is contained in:
commit
0eef82761f
5 changed files with 49 additions and 12 deletions
|
@ -4,6 +4,7 @@ v 8.5.0 (unreleased)
|
||||||
- Remove gray background from layout in UI
|
- Remove gray background from layout in UI
|
||||||
|
|
||||||
v 8.4.0 (unreleased)
|
v 8.4.0 (unreleased)
|
||||||
|
- Add pagination headers to already paginated API resources
|
||||||
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
|
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
|
||||||
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
|
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
|
||||||
- Improved performance of finding issues for an entire group (Yorick Peterse)
|
- Improved performance of finding issues for an entire group (Yorick Peterse)
|
||||||
|
|
|
@ -97,11 +97,9 @@ module API
|
||||||
end
|
end
|
||||||
|
|
||||||
def paginate(relation)
|
def paginate(relation)
|
||||||
per_page = params[:per_page].to_i
|
relation.page(params[:page]).per(params[:per_page].to_i).tap do |data|
|
||||||
paginated = relation.page(params[:page]).per(per_page)
|
add_pagination_headers(data)
|
||||||
add_pagination_headers(paginated, per_page)
|
end
|
||||||
|
|
||||||
paginated
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate!
|
def authenticate!
|
||||||
|
@ -329,16 +327,26 @@ module API
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def add_pagination_headers(paginated, per_page)
|
def add_pagination_headers(paginated_data)
|
||||||
|
header 'X-Total', paginated_data.total_count.to_s
|
||||||
|
header 'X-Total-Pages', paginated_data.total_pages.to_s
|
||||||
|
header 'X-Per-Page', paginated_data.limit_value.to_s
|
||||||
|
header 'X-Page', paginated_data.current_page.to_s
|
||||||
|
header 'X-Next-Page', paginated_data.next_page.to_s
|
||||||
|
header 'X-Prev-Page', paginated_data.prev_page.to_s
|
||||||
|
header 'Link', pagination_links(paginated_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_links(paginated_data)
|
||||||
request_url = request.url.split('?').first
|
request_url = request.url.split('?').first
|
||||||
|
|
||||||
links = []
|
links = []
|
||||||
links << %(<#{request_url}?page=#{paginated.current_page - 1}&per_page=#{per_page}>; rel="prev") unless paginated.first_page?
|
links << %(<#{request_url}?page=#{paginated_data.current_page - 1}&per_page=#{paginated_data.limit_value}>; rel="prev") unless paginated_data.first_page?
|
||||||
links << %(<#{request_url}?page=#{paginated.current_page + 1}&per_page=#{per_page}>; rel="next") unless paginated.last_page?
|
links << %(<#{request_url}?page=#{paginated_data.current_page + 1}&per_page=#{paginated_data.limit_value}>; rel="next") unless paginated_data.last_page?
|
||||||
links << %(<#{request_url}?page=1&per_page=#{per_page}>; rel="first")
|
links << %(<#{request_url}?page=1&per_page=#{paginated_data.limit_value}>; rel="first")
|
||||||
links << %(<#{request_url}?page=#{paginated.total_pages}&per_page=#{per_page}>; rel="last")
|
links << %(<#{request_url}?page=#{paginated_data.total_pages}&per_page=#{paginated_data.limit_value}>; rel="last")
|
||||||
|
|
||||||
header 'Link', links.join(', ')
|
links.join(', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def abilities
|
def abilities
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe API::API, api: true do
|
describe API::CommitStatus, api: true do
|
||||||
include ApiHelpers
|
include ApiHelpers
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:user2) { create(:user) }
|
let(:user2) { create(:user) }
|
||||||
|
@ -12,6 +12,10 @@ describe API::API, api: true do
|
||||||
let(:commit_status) { create(:commit_status, commit: ci_commit) }
|
let(:commit_status) { create(:commit_status, commit: ci_commit) }
|
||||||
|
|
||||||
describe "GET /projects/:id/repository/commits/:sha/statuses" do
|
describe "GET /projects/:id/repository/commits/:sha/statuses" do
|
||||||
|
it_behaves_like 'a paginated resources' do
|
||||||
|
let(:request) { get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user) }
|
||||||
|
end
|
||||||
|
|
||||||
context "reporter user" do
|
context "reporter user" do
|
||||||
let(:statuses_id) { json_response.map { |status| status['id'] } }
|
let(:statuses_id) { json_response.map { |status| status['id'] } }
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,10 @@ describe API::API, api: true do
|
||||||
before { project.team << [user, :reporter] }
|
before { project.team << [user, :reporter] }
|
||||||
|
|
||||||
describe "GET /projects/:id/noteable/:noteable_id/notes" do
|
describe "GET /projects/:id/noteable/:noteable_id/notes" do
|
||||||
|
it_behaves_like 'a paginated resources' do
|
||||||
|
let(:request) { get api("/projects/#{project.id}/issues/#{issue.id}/notes", user) }
|
||||||
|
end
|
||||||
|
|
||||||
context "when noteable is an Issue" do
|
context "when noteable is an Issue" do
|
||||||
it "should return an array of issue notes" do
|
it "should return an array of issue notes" do
|
||||||
get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
|
get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
|
||||||
|
|
20
spec/support/api/pagination_shared_examples.rb
Normal file
20
spec/support/api/pagination_shared_examples.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Specs for paginated resources.
|
||||||
|
#
|
||||||
|
# Requires an API request:
|
||||||
|
# let(:request) { get api("/projects/#{project.id}/repository/branches", user) }
|
||||||
|
shared_examples 'a paginated resources' do
|
||||||
|
before do
|
||||||
|
# Fires the request
|
||||||
|
request
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has pagination headers' do
|
||||||
|
expect(response.headers).to include('X-Total')
|
||||||
|
expect(response.headers).to include('X-Total-Pages')
|
||||||
|
expect(response.headers).to include('X-Per-Page')
|
||||||
|
expect(response.headers).to include('X-Page')
|
||||||
|
expect(response.headers).to include('X-Next-Page')
|
||||||
|
expect(response.headers).to include('X-Prev-Page')
|
||||||
|
expect(response.headers).to include('Link')
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue