Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to API proxies. #21

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions lib/grape/pagination.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ def paginate(collection)
:per_page => (params[:per_page] || settings[:per_page])
}
collection = ApiPagination.paginate(collection, options)
links = (header['Link'] || "").split(',').map(&:strip)
pages = ApiPagination.pages_from(collection)

links = (header['Link'] || "").split(',').map(&:strip)
url = request.url.sub(/\?.*$/, '')
pages = ApiPagination.pages_from(collection)
url = request.url.sub(/\?.*$/, '')
url = URI.parse(url).request_uri if settings[:relative_uri]

if settings[:exclude_base_path]
base_path_regexp = Regexp.new("^" + settings[:exclude_base_path])
url = url.sub(base_path_regexp, "")
end

pages.each do |k, v|
old_params = Rack::Utils.parse_query(request.query_string)
Expand All @@ -28,6 +34,25 @@ def paginate(collection)

base.class_eval do
def self.paginate(options = {})
# URIs can also be relative, useful when using API proxies.
#
# From RFC 5988 (Web Linking):
# "If the URI-Reference is relative, parsers MUST resolve it
# as per [RFC3986], Section 5.""
set :relative_uri, (options[:relative_uri] || false)

# When using API proxies, you probably want to hide base path
# from returned links since proxies point to your API base path
# directly making its own resources not have such base path.
#
# E.g.
# If your application has the following API resource:
# mywebsite.example.com/api/v1/resource.json
# And that's accessible though the following API proxy resource:
# myproxy.example.com/v1/resource.json
# You don't want links to return '/api/v1/...', but '/v1/...'.
set :exclude_base_path, (options[:exclude_base_path] || false)

set :per_page, (options[:per_page] || 25)
params do
optional :page, :type => Integer, :default => 1,
Expand Down
16 changes: 16 additions & 0 deletions spec/grape_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,19 @@
end
end
end

describe NumbersProxiedAPI do
describe 'GET #index' do
let(:links) { last_response.headers['Link'].split(', ') }
let(:total) { last_response.headers['Total'].to_i }

context 'with existing Link headers' do
before { get "/api/numbers", :count => 30 }

it 'should contain relative pagination Links without base path' do
expect(links).to include('</numbers?count=30&page=2>; rel="next"')
expect(links).to include('</numbers?count=30&page=3>; rel="last"')
end
end
end
end
5 changes: 4 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'support/numbers_controller'
require 'support/numbers_api'
require 'support/numbers_proxied_api'
require 'api-pagination'

if ENV['PAGINATOR']
Expand Down Expand Up @@ -31,6 +32,8 @@
config.order = 'random'

def app
NumbersAPI
# Allows us to test different API apps.
# e.g. NumbersApi, NumbersProxiedApi...
described_class
end
end
22 changes: 22 additions & 0 deletions spec/support/numbers_proxied_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'grape'
require 'api-pagination'

class NumbersProxiedAPI < Grape::API
format :json

# This namespace is here simulate that the API is nested in a directory.
# When using an API proxy, this base path vanishes since the proxy host
# is the new base. That's why we have 'exclude_base_path'.
namespace :api do
desc 'Return some paginated set of numbers'
paginate :per_page => 10,
:exclude_base_path => "/api",
:relative_uri => true
params do
requires :count, :type => Integer
end
get :numbers do
paginate (1..params[:count]).to_a
end
end
end