Commit 0eef8276 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

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
parents 0430c00c 1b08cd81
...@@ -4,6 +4,7 @@ v 8.5.0 (unreleased) ...@@ -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 ...@@ -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 ...@@ -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
......
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 ...@@ -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 ...@@ -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)
......
# 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment