GithubHelp home page GithubHelp logo

davidcelis / api-pagination Goto Github PK

View Code? Open in Web Editor NEW
686.0 15.0 136.0 195 KB

:page_facing_up: Link header pagination for Rails and Grape APIs.

License: MIT License

Ruby 100.00%
ruby api pagination rails grape kaminari willpaginate

api-pagination's Introduction

api-pagination

Paginate in your headers, not in your response body. This follows the proposed RFC-8288 standard for Web linking.

Installation

In your Gemfile:

# Requires Rails (Rails-API is also supported), or Grape
# v0.10.0 or later. If you're on an earlier version of
# Grape, use api-pagination v3.0.2.
gem 'rails', '>= 3.0.0'
gem 'rails-api'
gem 'grape', '>= 0.10.0'

# Then choose your preferred paginator from the following:
gem 'pagy'
gem 'kaminari'
gem 'will_paginate'

# Finally...
gem 'api-pagination'

Configuration (optional)

By default, api-pagination will detect whether you're using Pagy, Kaminari, or WillPaginate, and it will name headers appropriately. If you want to change any of the configurable settings, you may do so:

ApiPagination.configure do |config|
  # If you have more than one gem included, you can choose a paginator.
  config.paginator = :kaminari # or :will_paginate

  # By default, this is set to 'Total'
  config.total_header = 'X-Total'

  # By default, this is set to 'Per-Page'
  config.per_page_header = 'X-Per-Page'

  # Optional: set this to add a header with the current page number.
  config.page_header = 'X-Page'

  # Optional: set this to add other response format. Useful with tools that define :jsonapi format
  config.response_formats = [:json, :xml, :jsonapi]

  # Optional: what parameter should be used to set the page option
  config.page_param = :page
  # or
  config.page_param do |params|
    params[:page][:number] if params[:page].is_a?(ActionController::Parameters)
  end

  # Optional: what parameter should be used to set the per page option
  config.per_page_param = :per_page
  # or
  config.per_page_param do |params|
    params[:page][:size] if params[:page].is_a?(ActionController::Parameters)
  end

  # Optional: Include the total and last_page link header
  # By default, this is set to true
  # Note: When using kaminari, this prevents the count call to the database
  config.include_total = false
end

Pagy-specific configuration

Pagy does not have a built-in way to specify a maximum number of items per page, but api-pagination will check if you've set a :max_per_page variable. To configure this, you can use the following code somewhere in an initializer:

Pagy::DEFAULT[:max_per_page] = 100

If left unconfigured, clients can request as many items per page as they wish, so it's highly recommended that you configure this.

Rails

In your controller, provide a pageable collection to the paginate method. In its most convenient form, paginate simply mimics render:

class MoviesController < ApplicationController
  # GET /movies
  def index
    movies = Movie.all # Movie.scoped if using ActiveRecord 3.x

    paginate json: movies
  end

  # GET /movies/:id/cast
  def cast
    actors = Movie.find(params[:id]).actors

    # Override how many Actors get returned. If unspecified,
    # params[:per_page] (which defaults to 25) will be used.
    paginate json: actors, per_page: 10
  end
end

This will pull your collection from the json or xml option, paginate it for you using params[:page] and params[:per_page], render Link headers, and call ActionController::Base#render with whatever you passed to paginate. This should work well with ActiveModel::Serializers. However, if you need more control over what is done with your paginated collection, you can pass the collection directly to paginate to receive a paginated collection and have your headers set. Then, you can pass that paginated collection to a serializer or do whatever you want with it:

class MoviesController < ApplicationController
  # GET /movies
  def index
    movies = paginate Movie.all

    render json: MoviesSerializer.new(movies)
  end

  # GET /movies/:id/cast
  def cast
    actors = paginate Movie.find(params[:id]).actors, per_page: 10

    render json: ActorsSerializer.new(actors)
  end
end

Note that the collection sent to paginate must respond to your paginator's methods. This is typically fine unless you're dealing with a stock Array. For Kaminari, Kaminari.paginate_array will be called for you behind-the-scenes. For WillPaginate, you're out of luck unless you call require 'will_paginate/array' somewhere. Because this pollutes Array, it won't be done for you automatically. If you use Pagy, it doesn't matter, because Pagy doesn't care what you're paginating. It will just work, as long as the collection responds to count.

NOTE: In versions 4.4.0 and below, the Rails::Pagination module would end up included in ActionController::Base even if ActionController::API was defined. As of version 4.5.0, this is no longer the case. If for any reason your API controllers cannot easily changed be changed to inherit from ActionController::API instead, you can manually include the module:

class API::ApplicationController < ActionController::Base
  include Rails::Pagination
end

Grape

With Grape, paginate is used to declare that your endpoint takes a :page and :per_page param. You can also directly specify a :max_per_page that users aren't allowed to go over. Then, inside your API endpoint, it simply takes your collection:

class MoviesAPI < Grape::API
  format :json

  desc 'Return a paginated set of movies'
  paginate
  get do
    # This method must take an ActiveRecord::Relation
    # or some equivalent pageable set.
    paginate Movie.all
  end

  route_param :id do
    desc "Return one movie's cast, paginated"
    # Override how many Actors get returned. If unspecified,
    # params[:per_page] (which defaults to 25) will be used.
    # There is no default for `max_per_page`.
    paginate per_page: 10, max_per_page: 200
    get :cast do
      paginate Movie.find(params[:id]).actors
    end

    desc "Return one movie's awards, paginated"
    # Enforce max_per_page value will add the alowed values
    # to the swagger docs, and cause grape to return an error
    # if outside that range
    paginate per_page: 10, max_per_page: 200, enforce_max_per_page: true
    get :awards do
      paginate Movie.find(params[:id]).awards
    end
  end
end

Headers

Then curl --include to see your header-based pagination in action:

$ curl --include 'https://localhost:3000/movies?page=5'
HTTP/1.1 200 OK
Link: <http://localhost:3000/movies?page=1>; rel="first",
  <http://localhost:3000/movies?page=173>; rel="last",
  <http://localhost:3000/movies?page=6>; rel="next",
  <http://localhost:3000/movies?page=4>; rel="prev"
Total: 4321
Per-Page: 10
# ...

A Note on Kaminari and WillPaginate

api-pagination requires either Kaminari or WillPaginate in order to function, but some users may find themselves in situations where their application includes both. For example, you may have included ActiveAdmin (which uses Kaminari for pagination) and WillPaginate to do your own pagination. While it's suggested that you remove one paginator gem or the other, if you're unable to do so, you must configure api-pagination explicitly:

ApiPagination.configure do |config|
  config.paginator = :will_paginate
end

If you don't do this, an annoying warning will print once your app starts seeing traffic. You should also configure Kaminari to use a different name for its per_page method (see https://github.com/activeadmin/activeadmin/wiki/How-to-work-with-will_paginate):

Kaminari.configure do |config|
  config.page_method_name = :per_page_kaminari
end

api-pagination's People

Contributors

adrientoub avatar bruce avatar codeodor avatar coffeejunk avatar davidcelis avatar digitaltom avatar domon avatar eidge avatar eitoball avatar ekampp avatar fotos avatar hbin avatar jirichara avatar kamui avatar lcpmarvel avatar leods92 avatar mach-kernel avatar magnusfiorepalm avatar maries1415 avatar marlonandrade avatar mislav avatar monfresh avatar nicolasleger avatar petergoldstein avatar skcc321 avatar stefschenkelaars avatar titeiko avatar tonycidme avatar trev avatar zabolotnov87 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

api-pagination's Issues

Cannot override per_page

Hey, after updating to 3.0.1 my clients cannot override the per_page variable at all. Previously, my signature under 2.1.1 looked like this:

paginate per_page: 25
params do
  # ...
end
get do
  # ...
end

However even after changing it to what is suggested at the end of #10, it cannot be overridden at all. The 'set :per_page, 30' is effective in setting the default, but it does not allow it to be changed by the client code afterwards. I've reverted back to 2.1.1 for now. Any ideas?

Not correctly limiting per_page

I have this in my API Customers controller

class Api::V1::CustomersController < ApplicationController
  before_filter :fetch_account
  after_filter only: [:index] { paginate(:customers) }

  def index
    @customers = @account.customers
    params[:per_page] = 1
    render json: @customers
  end
end

and this in my rails app

gem 'will_paginate', '~> 3.0'
gem 'api-pagination'

But when I hit my API route for customers it still lists them all out instead of 1 per page.

Set current page

This is my config of pagination:

config.page_param do |params|
  params[:page][:number]
end

config.per_page_param do |params|
  params[:page][:size]
end

I have 40 records. I want to get record beginning with id 11. When I pass pages parameters : page: {number: 2, per_page: 10} I have got records beginning with id: 1

paginate json: users, per_page: params[:page][:size], page: params[:page][:number]
What am I doing wrong?

Setting a default per_page value in Grape

Is there a recommended way to set a default per_page setting for a single route? A few of my routes do pagination, but have different defaults. The only way I've managed to get this working is this:

  paginate
  params do
    optional :per_page,
             type: Integer,
             default: 30,
             desc: "Number of results to return per page."
  end

While this works, paginate already defined this param. It would be cool if the paginate method could take a default per_page argument or maybe a hash value? Or maybe there's a better way to do this?

Undefined method paginate on Rails 5.0.1

NoMethodError - undefined method `paginate' for #<UsersController:0x007fedd643de08>:

It seems to be because in Rails 5, ActionContoller::API is defined in a standard rails new dummy application.

So https://github.com/davidcelis/api-pagination/blob/master/lib/api-pagination/hooks.rb#L8 works for rails api only applications, but not regular rails applications.

It seems that since both ActionController::Base and ActionController::API inherit from ActionController::Metal, maybe that would be a better place to add the hook.

Is there a default sort order on :id enforced?

I'm specifying that records get sorted by name but what I'm seeing is that the paginated result set is being ordered by :id, :name. Is this expected? It seems that it prevents any sorting at all which would make me sad. If I'm missing something, it isn't obvious. Please advise.

      def index
        pp sort_order  #=> :name
        @users = _paginate_collection(User.where(id: associated_user_ids).order(sort_order),
                                      per_page: pagination_items_per_page,
                                      page: page_requested)
      end

Results in SQL:

User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 5, 6,... 288)  ORDER BY "users"."id" ASC, "users"."name" ASC LIMIT 50 OFFSET 0

Getting "undefined method `each' for 0:Fixnum" when using this gem with Kaminari

Nice gem! This is exactly what I need except i'm getting the following server error when using api-pagination in conjunction with kaminari.

Running curl -I localhost:3000/tests.json?page=1 I get

Unexpected error while processing request: undefined method `each' for 100:Fixnum
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/response.rb:73:in `block in headers='
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/rack-1.5.2/lib/rack/utils.rb:451:in `block in each'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/rack-1.5.2/lib/rack/utils.rb:450:in `each'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/rack-1.5.2/lib/rack/utils.rb:450:in `each'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/response.rb:68:in `headers='
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/connection.rb:98:in `post_process'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/connection.rb:55:in `process'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/connection.rb:41:in `receive_data'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/eventmachine-1.0.3/lib/eventmachine.rb:187:in `run_machine'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/eventmachine-1.0.3/lib/eventmachine.rb:187:in `run'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/backends/base.rb:73:in `start'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/thin-1.6.1/lib/thin/server.rb:162:in `start'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/rack-1.5.2/lib/rack/handler/thin.rb:16:in `run'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/rack-1.5.2/lib/rack/server.rb:264:in `start'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/railties-4.0.2/lib/rails/commands/server.rb:84:in `start'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/railties-4.0.2/lib/rails/commands.rb:76:in `block in <top (required)>'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/railties-4.0.2/lib/rails/commands.rb:71:in `tap'
    /Users/deepanchor/.rvm/gems/ruby-1.9.3-p327/gems/railties-4.0.2/lib/rails/commands.rb:71:in `<top (required)>'
    bin/rails:4:in `require'
    bin/rails:4:in `<main>'

My controller:

class TestsController < ApplicationController
  after_filter only: [:index] { paginate(:tests) }

  def index
    @tests = Test.all
    render json: @tests

  end
end

Gemfile

gem 'kaminari'
gem 'api-pagination'

I created a new app to reproduce this error: https://github.com/DeepAnchor/api-pagination-test.git

Doesn't work anymore with multi word classes

Since the commit 906b096 the paginate method returns a LoadError when a class related to a table with an underscore in the name is used.

For instance here the class is called PromotionCode and the code looks for a Promotion_code which is obviously wrong.

LoadError:
  Unable to autoload constant Promotion_code, expected .../app/models/promotion_code.rb to define it
# .../api-pagination-4.6.2/lib/api-pagination.rb:85:in `detect_model'
# .../api-pagination-4.6.2/lib/api-pagination.rb:78:in `default_per_page_for_will_paginate'
# .../api-pagination-4.6.2/lib/api-pagination.rb:57:in `paginate_with_will_paginate'
# .../api-pagination-4.6.2/lib/api-pagination.rb:15:in `paginate'
# .../api-pagination-4.6.2/lib/rails/pagination.rb:30:in `_paginate_collection'
# .../api-pagination-4.6.2/lib/rails/pagination.rb:9:in `paginate'
...

The line 85 of the code is obviously wrong, this only works for single words class:

        collection.table_name.singularize.capitalize.constantize

2.0.0 yanked?

Hi… just a question… why did you yank version 2.0.0 from rubygems?

Did it have any security issue? Thanks

Configuration from readme not working

I just copied full configuration from readme, moved it to initializers folder and got this:

/config/initializers/api-pagination.rb:15:in `block in <top (required)>': undefined method `page_param=' for #<ApiPagination::Configuration:0x00000001fa6210> (NoMethodError)
Did you mean?  page_header=

P.S. After that I figured out I don't need the configuration for this gem. Actually I needed configuration for kaminari (to change default of per_page). But keep in mind there is a problem with configuration file (or you have to add some explanation to readme if it's not obviously to use that).

Support for Pagy

Pagy is a new "pagination gem that outperforms the others in each and every benchmark and comparison".

Would this paginator be something api-pagination could support?

Access Link header in fetch response

I'm consuming an API that I paginated with your gem. How would I gain access to the link header in the fetch response? I am using React to consume the endpoint, right now when I try response.headers it's just an empty json object.

    fetch('url')
      .then(response => {
        return response.json()})
      .then(data => {
        this.setState({recomms: data})
        localStorage.setItem('movies', JSON.stringify(data))
       })

Links don't match actual params

This gem allows the use of custom page size and number params. However,

new_params = request.query_parameters.merge(:page => v)
seems to indicate that regardless of the params set, it assumes that the page number param is just called :page. Shouldn't that be keyed off the configuration instead?

Release version of the gem

Hi @davidcelis! Thanks for this gem, its been great. Wondering if you plan to cut a release for the gem containing changes in master since the Feb and what the timing for that might look like?

Kaminari will_paginate conflict

Hi.
I am using will_paginate as paginator.
However rails_admin use kaminari as default paginator.

In ApiPagination::Hooks.init

      begin; require 'will_paginate'; rescue LoadError; end
      if defined?(WillPaginate::CollectionMethods)
        WillPaginate::CollectionMethods.module_eval do
          def first_page?() !previous_page end
          def last_page?() !next_page end
        end

        ApiPagination.instance_variable_set(:@paginator, :will_paginate)
      end

      begin; require 'kaminari'; rescue LoadError; end
      if defined?(Kaminari)
        ApiPagination.instance_variable_set(:@paginator, :kaminari)
      end

You set @Paginator attribute with kaminari even if it already was initialized. You may add if blank? check, but i think this may cause other problems and is not a good solution.

Edge cases when records change in the middle of paginating

Here's a pretty good description: http://stackoverflow.com/questions/13872273/api-pagination-best-practices

Like many APIs, this one paginates large results. If you query /foos, you'll get 100 results (i.e. foo #1-100), and a link to /foos?page=2 which should return foo #101-200.

Unfortunately, if foo #10 is deleted from the data set before the API consumer makes the next query, /foos?page=2 will offset by 100 and return foos #102-201.

This is a problem for API consumers who are trying to pull all foos - they will not receive foo #101.

I'm not sure if I believe that api-pagination should handle this out-of-the-box, but I'm trying to automatically append an ?until=TIMESTAMP parameter to my Link header, and I've ended up with a pretty terrible monkeypatch:

img

I'm wondering if the author / maintainers have thought about this at all, and what would be an acceptable solution?

Access pagination details in json

While its great to have the pagination inside the headers, is it possible to render out these details such as next_page_url, total_items in the json view?

I tried using kaminari's page local var but it wasnt available.

how to use Grape::Entity in api-pagination?

desc "最新Tweet 验证:是 可选参数::page 返回第page页的数据 and :per_page 每页返回per_page条数据 默认5条"
    paginate per_page: 5, max_per_page: 20
    get do
      authenticate!
      #present current_user.feed, with: APIEntities::Tweet
      paginate current_user.feed, with: APIEntities::Tweet
    end

this has a error

ArgumentError (wrong number of arguments (2 for 1)):

APIs are vulnerable to infinite listing with params[:per_page]

I think we should discuss about the params[:per_page] that api-pagination makes automatically exposed/allowed when using Grape.
There's currently no limit set what allows anyone to fetch tons of records at once.

What if we add another config option :max_per_page that limits that?
I think that we can then make params[:per_page] limited to the :per_page config by default.

This could break some APIs that rely on params[:per_page] to be unlimited.

What should we do?

Bug when parameters are empty string

When a parameter is included in a request but is a blank empty string, there is unexpected and buggy behavior.

  • When params[:page] == "", #to_i is called on it, which causes the page to default to 0. Normally, the first page is 1. This may be equivalent now, but in the future may cause unintended consequences.
  • When params[:per_page] == "", this causes the error: "comparison of Fixnum with String failed".

I propose that when a parameter is included but is empty string that more defined behavior occurs such as falling back to a default.

  • params[:page] should default to 1
  • params[:per_page] should default to route_setting(:per_page).

Is there a way to globally set per-page number?

By default, per-page number is 30. I can set it when I am returning my results but that's a little hard to manage if I have lots of APIs. Is there a configuration to globally set a default per-page number? Thanks

Per page in response?

Hi,

Hi I'm using the response in this API together with a javascript/HTML pagination library which shows a nice pagination toolbar to the user. However this pagination library needs the per_page to work. I would expect this to be the case with many other libraries/use_cases as well.

Would it be possible to get a per page in the response similar to the total which is provided in the current gem?

I know there are two work arounds:

  1. I could probably do something clever and parse it from the link part of the header response. However this seems hackish and a bit unreliable.
  2. I could manually set per_page in both my javascript and rails controller code. This is not DRY so I would prefer to avoid it.

Caching and Pagination ?

Hi, I'm having a little trouble getting Rails caching to play nicely with this gem. Here's some psuedo code that matches my code fairly well:

# Shows HTTP paging headers, but loads everything into memory
def user_posts
  cache_key = {
    user_id: current_user.id, 
    latest_post: current_user.posts.maximum(:updated_at)
  }

  posts = Rails.cache.fetch(cache_key) do
     current_user.posts.order('created_at DESC')
  end
  render json: paginate(posts), each_serializer: PostSerializer
end

If I do this, I will get the api_pagination HTTP headers. However, I'm loading all of the current_user's posts into memory, which seems like a bad thing.

If I paginate inside the caching block (like below), then I don't get any api_pagination HTTP headers.

# Doesn't show HTTP paging headers, but doesn't load everything into memory
def user_posts
  cache_key = {
    user_id: current_user.id, 
    latest_post: current_user.posts.maximum(:updated_at), 
    page: params[:page]
  }

  posts = Rails.cache.fetch(cache_key) do
     paginate(current_user.posts.order('created_at DESC'))
  end
  render json: posts, each_serializer: PostSerializer
end

Can someone point me in the right direction? I'm having a hard time googling for API Pagination and Rails caching. Perhaps I'm missing something fairly obvious. I'm using kaminari, if that helps.

Thanks so much!

ActionView::MissingTemplate when passing in the template or action options

Code looks like this:

module Api
  module V1
    class TeamsController < ApiController
      def mine
        @teams = current_user.teams
        paginate @teams, action: 'index'
      end
    end
  end
end

If I change it to render and drop the collection, it renders as expected (minus the headers this gem adds). However, if I try to paginate, it all of the sudden looks for the mine template instead of the specified index template.

If I change it to paginate json: @teams, action: 'index' it does not use my template at all, resulting in an information leak (I'm assuming it just calls as_json on the AR collection).

Support for without_count?

Kaminari has a method called without_count. It creates a paginatable collection without counting the number of all records. The usage is

User.page(3).without_count

It's on the kaminari docs.
Is there currently support for this? If not, would you consider adding it?

Problem with jbuilder

Hey, I was looking into using your gem, but I can't get it working with jbuilder. Is this something that you'd like the gem to support? If it doesn't.

Unless I'm doing something wrong (entirely possible!) I think it's due to the explicit :json key that gets added to the render options in the "paginate" method.

Rails it only seems to render the jbuilder template if you don't specify a json key in the call to render. e.g. this works:

@collection = some_paginated_collection
render :index, status: :ok

but this doesn't:

    render json: @collection

Let me know your thoughts. I'd like to help fix it if this is a problem.

problem when migrating from will_paginate to pagy with api-pagination

Hello,
I am trying to migrate from will_paginate to api-pagination, but I encounter the following problem:

I get my collection with the following request:

@contents = Content.select("distinct on (contents.name) contents.*")
This request is working and does the expected behavior when run in console.

And I would like to paginate it using api-pagination and pagy:

@contents = paginate @contents

This triggers the following error:
PG::SyntaxError: ERROR: syntax error at or near "on" LINE 1: SELECT COUNT(distinct on (contents.name) contents.) FROM "c... ^ : SELECT COUNT(distinct on (contents.name) contents.) FROM "contents"

But I cannot see which line it comes from.

It is likely that it does not come from pagy (issue pagy)

api-pagination 4.5.0 support for Rails 4.2.x broken?

The update for Rails 5 support has in some way broken support for Rails 4.2. Reverting to api-pagination 4.4.0 restores working support for Rails 4.2. On rails server startup the following trace occurs in Rails 4.2.x with api-pagination 4.5.0:

Bundler::GemRequireError: There was an error while trying to load the gem 'api-pagination'.
Gem Load Error is: uninitialized constant ApiPagination::Hooks
Backtrace for gem load error is:
/var/lib/jenkins/.rvm/gems/ruby-2.1.7/gems/api-pagination-4.5.0/lib/api-pagination/hooks.rb:7:in `block in <top (required)>'

Adding api-pagination to gemfile breaks all jbuilder rendering

What versions: api-pagination version 4.4.0+
Rails: 5.1.6
Pagination gem: Kaminari 1.1.1
jbuilder: 2.7.0

Expected behavior:
Adding paginate to an ActiveRecord query should add pagination headers to the response and paginate the query result.

Actual behavior:
200 OK with pagination headers but empty body, no json whatsoever.

Also non-paginated requests are broken.

Steps to reproduce:

  1. Clone this branch of my repo: https://github.com/PinsterTeam/PinsterApi/tree/newell/api_pagination_broken
  2. Setup database etc.
  3. Seed database with rails seed_data
  4. Execute GET on http://0.0.0.0:3000/v1/pins and observe empty response
  5. Remove api-pagination gem from gemfile
  6. Comment/remove config initializer
  7. Remove paginate call from index action in v1/pins_controller
  8. Execute GET on http://0.0.0.0:3000/v1/pins and observe very large response

I'm interested in this gem so let me know if there's anything I can do to help track down the issue.

Not paginating when using each_serializer

Hi @davidcelis! This might be a n00b mistake but in my setup, I can't get the pagination to work when using each_serializer option. In other words, if I do API_URL?page=2, it returns the same set of results.

I am using Rails 4.2.4 with AMS 0.9.3 and Kaminari. Here is the relevant code in the controller:

paginate json:      posts,
each_serializer:    PostSerializer,
page:           params[:page],
per_page:       20

If I comment out each_serializer above, then it works fine.

Any pointers would be helpful, and thank you again for the gem!

Add option to turn off total count

I ahve an issue with an api I'm working on that queries against a collection wit millions of records. I want to return the Link header but not the total to avoid the extra query call for total count.

It would be nice if this was a configurable option.

Multiple rels and urls in the same Link element

Api-pagination is adding multiple links and multiple relation types in the
same Link header which seems not correct as per RFC https://tools.ietf.org/html/rfc5988.
Check the example in point 5 and description 5.3.

Shouldn't it look like this?

Link: <http://localhost:3000/movies?page=1>; rel="first"
Link: <http://localhost:3000/movies?page=173>; rel="last"
Link: <http://localhost:3000/movies?page=6>; rel="next"
Link: <http://localhost:3000/movies?page=4>; rel="prev"

Group json data

How can I group json data by table name, e.g, name or sku?

# method 1
def product_data
    products = paginate Product.all, per_page: 20
    render json: JSON.pretty_generate(product_data.as_json)
  end

The above method produced the following, please click link to check - https://deaninfotech.herokuapp.com/products.json

I want to be able to group the products by sku or by name? How can I get a work around it?

I wrote this method, which didn't give the desired result

# method 2
def product_data
    products = paginate Product.all, per_page: 20
    grouped_products = products.group_by{ |product| product['name']['AP'] }.values
    product_data = grouped_products
    render json: JSON.pretty_generate(product_data.as_json)
  end

The desired result is that I want to be able to group all Products in the database, even before paginating them.

The reason why it is necessary to group the objects before paginating is that I noticed after grouping with method 2 above, I found that the objects were not fully grouped together.
Next page is showing more products from an already grouped object in the previous page.

I want to render the returned grouped products, and then paginate it into 20 grouped products per page.

How can I achieve this result, please?

I read some post that suggested Filtering and Grouping objects in the database in postgres before actually sending it to rails. But still, don't know how to achieve this. Any help or links would be appreciated, thanks.

Empty collection expects no Link in headers

My API goes to http://localhost:3000/api/v1/posts?user_id=6&mine=true&scope=finished

When server returns empty collection, the headers includes 2 links:

Link: <http://localhost:3000/api/v1/posts?mine=true&page=0&scope=finished&user_id=6>; rel="last", <http://localhost:3000/api/v1/posts?mine=true&page=2&scope=finished&user_id=6>; rel="next"
Per-Page: 25
Total: 0

When I go to the next page:

http://localhost:3000/api/v1/posts?mine=true&page=2&scope=finished&user_id=6

returns 4 links:

Link:<http://localhost:3000/api/v1/posts?mine=true&page=1&scope=finished&user_id=6>; rel="first", <http://localhost:3000/api/v1/posts?mine=true&page=1&scope=finished&user_id=6>; rel="prev", <http://localhost:3000/api/v1/posts?mine=true&page=0&scope=finished&user_id=6>; rel="last", <http://localhost:3000/api/v1/posts?mine=true&page=3&scope=finished&user_id=6>; rel="next"
Per-Page:25
Total:0

But when I got 1 object returned there is no Link in headers:

Cache-Control:max-age=0, private, must-revalidate
ETag:W/"92cf8ffe479fc045a7dcc2386a9df92e"
Per-Page:25
Total:1
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:515c32d3-6b73-40fd-b444-7629aa2656cc
X-Runtime:0.013192
X-XSS-Protection:1; mode=block

Since there is no Link in headers when server return all collection in one page, I think it is expects no Link in headers too when server returns empty collection.

Support will_paginate's config

is there a reason not to support will_paginate's (and I guess kaminari's as well, but I haven't used that) pagination options?

e.g.

class Post
  self.per_page = 2
end

paginate Post.all

but in the response headers I get

Per-Page: 30

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.