Skip to content
Merged
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
104 changes: 53 additions & 51 deletions CHANGELOG.md

Large diffs are not rendered by default.

20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -790,14 +790,32 @@ See [Strava::Errors::UploadError](lib/strava/errors/upload_failed_error.rb) for

### Pagination

Some Strava APIs, including [athlete-activities](#list-athlete-activities) support pagination when supplying an optional `page` and `per_page` parameter. By default the client retrieves one page of data, which Strava currently defaults to 30 items. You can paginate through more data by supplying a block and an optional `per_page` parameter. The underlying implementation makes page-sized calls and increments the `page` argument.
Some Strava APIs, including [athlete-activities](#list-athlete-activities) support pagination when supplying an optional `page` and `per_page` parameter. By default the client retrieves one page of data, which Strava currently defaults to 30 items. If you supply `per_page`, the client will retrieve all pages. You can paginate through items incrementally by supplying a block. Use `limit` to limit the number of items returned. The underlying implementation makes page-sized calls and increments the `page` argument.

```ruby
client.athlete_activities(per_page: 30) do |activity|
activity # => Strava::Models::Activity
end
```

```ruby
client.athlete_activities(per_page: 30) # => [Strava::Models::Activity], all pages
client.athlete_activities(per_page: 30, limit: 50) # => [Strava::Models::Activity], all pages, stop at 50 items
```

Some Strava APIs, including [activity-comments](#list-activity-comments) support cursor-based pagination when supplying optional `after_cursor` and `page_size` parameters. By default the client retrieves one page of data, which Strava currently defaults to 30 items. If you supply `page_size`, the client will retrieve all pages. You can paginate through items incrementally by supplying a block. Use `limit` to limit the number of items returned. The underlying implementation makes page-sized calls and uses the returned `cursor` as `after_cursor`.

```ruby
client.activity_comments(id: 1982980795, page_size: 30) do |comment|
comment # => Strava::Models::Comment
end
```

```ruby
client.activity_comments(id: 1982980795, page_size: 30) # => [Strava::Models::Comment], all pages
client.activity_comments(id: 1982980795, page_size: 30, limit: 100) # => [Strava::Models::Comment], paginated, stop at 100 items
```

### OAuth

#### OAuth Workflow
Expand Down
25 changes: 25 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,31 @@ This change fixes the `Hashie::Trash` serialization warning that occurred when u

See [#92](https://github.com/dblock/strava-ruby-client/pull/92) for details.

#### Always Paginate with `per_page` or `page_size`

The client will always paginate data if `per_page` or `page_size` are provided.

**Before (v2.x):**
```ruby
# one request for a page of 10 items
client.activity_comments(id: 1982980795, page_size: 10) # => [Strava::Models::Comment]
```

**After (v3.0.0):**
```ruby
# all pages, multiple requests, potentially more than 10 items
client.activity_comments(id: 1982980795, page_size: 10) # => [Strava::Models::Comment]
```

Use `limit` in combination with `page_size` to both paginate and retrieve a certain number of items.

```ruby
# all pages, 10 items per page, no more than 20 items
client.activity_comments(id: 1982980795, page_size: 10, limit: 20) # => [Strava::Models::Comment]
```

See [#99](https://github.com/dblock/strava-ruby-client/pull/99) for details.

### Upgrading to >= 2.3.0

Faraday can optionally exclude HTTP method, path and query params from the errors raised. The client implementation options will now default to `Faraday::Response::RaiseError::DEFAULT_OPTIONS` with `include_request` set to `true`. You can change this behavior by setting `Strava::Web::RaiseResponseError::DEFAULT_OPTIONS`.
Expand Down
43 changes: 38 additions & 5 deletions lib/strava/api/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def config
private

#
# paginates requests
# Paginates requests using per_page.
#
# @param [String] path url for request
# @param [Hash] options hash containing settings
Expand All @@ -51,21 +51,54 @@ def config
#
# @return [Strava::Api::Pagination]
#
def paginate(path, options, model)
def paginate(path, options, model, &block)
raise ArgumentError, 'per_page' if options.key(:page_size)

paginate_with_cursor(path, options, model, &block)
end

#
# Paginates requests using a cursor, using per_page or page_size.
#
# @param [String] path url for request
# @param [Hash] options hash containing settings
# @param [Class] model by Class
#
# @example
# paginate("activity/comments", {page_size: 72}, Strava::Models::Comment)
# paginate("athlete/activities", {per_page: 72}, Strava::Models::Activity)
#
# @return [Strava::Api::Pagination]
#
def paginate_with_cursor(path, options, model)
# avoid retrieving unnecessary items
options = options.merge(per_page: options[:limit]) if options.key?(:per_page) && options.key(:limit) && options[:per_page] > options[:limit]
options = options.merge(page_size: options[:limit]) if options.key?(:page_size) && options.key(:limit) && options[:page_size] > options[:limit]
collection = []
web_response = nil
if block_given?
if block_given? || options.key?(:page_size) || options.key(:per_page)
Cursor.new(self, path, options).each do |page|
web_response = page # response of the last request made
page.each do |row|
break if options.key?(:limit) && collection.size >= options[:limit]

m = model.new(row)
yield m
yield m if block_given?
collection << m
end
end
else
web_response = get(path, options)
page_options = if options.key?(:limit)
options.dup.tap do |copy|
copy[:page_size] = copy.delete(:limit)
end
else
options
end
web_response = get(path, page_options)
collection = web_response.map do |row|
break if options.key?(:limit) && collection.size >= options[:limit]

model.new(row)
end
end
Expand Down
28 changes: 26 additions & 2 deletions lib/strava/api/cursor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ class Cursor
def initialize(client, path, params = {})
@client = client
@path = path
@params = params
@params = params.key?(:limit) ? params.dup.tap { |p| p.delete :limit } : params
end

def each
def each(&block)
params[:page_size] ? each_cursor(&block) : each_page(&block)
end

private

def each_page
next_page = 1
loop do
query = params.merge(page: next_page)
Expand All @@ -24,6 +30,24 @@ def each
next_page += 1
end
end

def each_cursor
cursor = nil
query = params
loop do
response = client.get(path, query)
break unless response.any?

yield response

break if response.size < params[:page_size]

cursor = response.last&.[]('cursor')
break unless cursor.present?

query = params.merge(after_cursor: cursor)
end
end
end
end
end
5 changes: 4 additions & 1 deletion lib/strava/api/endpoints/activities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ def activity(id_or_options, options = {})
# Activity id.
# @option options [Integer] :page
# Page number.
# @option options [Integer] :page_size
# Number of items per page. Defaults to 30.
# @option options [Integer] :per_page
# Number of items per page. Defaults to 30.
# @deprecated use {page_size}
#
def activity_comments(id_or_options, options = {}, &block)
id, options = parse_args(id_or_options, options)
paginate "activities/#{id}/comments", options, Strava::Models::Comment, &block
paginate_with_cursor "activities/#{id}/comments", options, Strava::Models::Comment, &block
end

#
Expand Down
3 changes: 1 addition & 2 deletions lib/strava/api/pagination.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ def initialize(collection, web_response)
# @return [Strava::Web::ApiResponse]
#
def http_response
@http_response ||=
Strava::Web::ApiResponse.new(deep_copy(@web_response).http_response)
@http_response ||= Strava::Web::ApiResponse.new(deep_copy(@web_response).http_response)
end

#
Expand Down
80 changes: 80 additions & 0 deletions spec/fixtures/strava/client/activity_comments_by_10.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading