diff --git a/README.md b/README.md index bc25fb77..94fbf7be 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ API Usage Examples ------------------ require "rubygems" require "instagram" - + # All methods require authentication (either by client ID or access token). # To get your Instagram OAuth credentials, register an app at http://instagr.am/oauth/client/register/ Instagram.configure do |config| @@ -84,6 +84,15 @@ API Usage Examples page_2_max_id = page_1.pagination.next_max_id page_2 = Instagram.user_recent_media(777, :max_id => page_2_max_id ) unless page_2_max_id.nil? + # Get next page of data from response + page_1 = Instagram.user_recent_media(777) + page_2 = page_1.next + + # Inspect rate limit data provided by Instagram API (5000 requests/client id/hour, 5000 requests/access token/hour) + page_1 = Instagram.user_recent_media(777) + limit = page_1.ratelimit.limit + remaining = page1.ratelimit.remaining + # Get the currently authenticated user's media feed puts Instagram.user_media_feed @@ -105,7 +114,7 @@ API Usage Examples # Search for a location by Fousquare ID (v2) puts Instagram.location_search("3fd66200f964a520c5f11ee3") - + Contributing diff --git a/lib/instagram/request.rb b/lib/instagram/request.rb index 03db3b7e..a78bb94a 100644 --- a/lib/instagram/request.rb +++ b/lib/instagram/request.rb @@ -37,7 +37,8 @@ def request(method, path, options, raw=false, unformatted=false, no_response_wra end return response if raw return response.body if no_response_wrapper - return Response.create( response.body ) + return Response.create( response.body, {:limit => response.headers['x-ratelimit-limit'].to_i, + :remaining => response.headers['x-ratelimit-remaining'].to_i} ) end def formatted_path(path) diff --git a/lib/instagram/response.rb b/lib/instagram/response.rb index d27784b3..42944740 100644 --- a/lib/instagram/response.rb +++ b/lib/instagram/response.rb @@ -1,16 +1,29 @@ module Instagram module Response - def self.create( response_hash ) + def self.create( response_hash, ratelimit_hash ) data = response_hash.data.dup rescue response_hash data.extend( self ) data.instance_exec do @pagination = response_hash.pagination @meta = response_hash.meta + @ratelimit = ::Hashie::Mash.new(ratelimit_hash) end data end + def next + if pagination.next_url + client = Instagram.client(Instagram.options) + pagination.next_url.sub!('http://', 'https://') #Make the URL secure if it isn't already + response = client.get(pagination.next_url.sub(Instagram.endpoint, ''), {}, false, true) + response + else + [] + end + end + attr_reader :pagination attr_reader :meta + attr_reader :ratelimit end end diff --git a/spec/fixtures/user_media_feed_next.json b/spec/fixtures/user_media_feed_next.json new file mode 100644 index 00000000..d11abc07 --- /dev/null +++ b/spec/fixtures/user_media_feed_next.json @@ -0,0 +1 @@ +{"pagination": {}, "meta": {"code": 200}, "data": []} \ No newline at end of file diff --git a/spec/instagram/client/users_spec.rb b/spec/instagram/client/users_spec.rb index b483fd66..914c1c9e 100644 --- a/spec/instagram/client/users_spec.rb +++ b/spec/instagram/client/users_spec.rb @@ -160,6 +160,9 @@ stub_get("users/self/feed.#{format}"). with(:query => {:access_token => @client.access_token}). to_return(:body => fixture("user_media_feed.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) + + stub_get("users/self/feed?access_token=f59def8.001cde77128843169627c0308237bafa&max_id=22063131"). + to_return(:body => fixture("user_media_feed_next.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end it "should get the correct resource" do @@ -171,6 +174,7 @@ context Instagram::Response do let(:user_media_feed_response){ @client.user_media_feed } + let(:next_url){ 'http://api.instagram.com/v1/users/self/feed?access_token=f59def8.001cde77128843169627c0308237bafa&max_id=22063131' } subject{ user_media_feed_response } it{ should be_an_instance_of(Array) } @@ -182,7 +186,7 @@ subject{ user_media_feed_response.pagination } it{ should be_an_instance_of(Hashie::Mash) } - its(:next_url){ should == 'http://api.instagram.com/v1/users/self/feed?access_token=f59def8.001cde77128843169627c0308237bafa&max_id=22063131' } + its(:next_url){ should == next_url } its(:next_max_id){ should == '22063131' } end @@ -192,11 +196,27 @@ it{ should be_an_instance_of(Hashie::Mash) } its(:code){ should == 200 } end + + context 'next' do + subject{ user_media_feed_response } + + it{ should respond_to(:next) } + + it "should handle a next call correctly" do + next_feed = user_media_feed_response.next + a_get(next_url.sub('http://api.instagram.com/v1/', '')).should have_been_made + next_feed.should be_an_instance_of(Array) + next_feed.should be_a_kind_of(Instagram::Response) + next_feed.pagination.should be_empty + next_feed.next.should be_empty + end + end + end end describe ".user_liked_media" do - + before do stub_get("users/self/media/liked.#{format}"). with(:query => {:access_token => @client.access_token}). @@ -210,7 +230,7 @@ should have_been_made end end - + describe ".user_recent_media" do context "with user ID passed" do @@ -273,148 +293,148 @@ users.first.username.should == "shayne" end end - + describe ".user_relationship" do - + before do stub_get("users/4/relationship.#{format}"). with(:query => {:access_token => @client.access_token}). to_return(:body => fixture("relationship.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.user_relationship(4) a_get("users/4/relationship.#{format}"). with(:query => {:access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.user_relationship(4) status.incoming_status.should == "requested_by" end end - + describe ".follow_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "follow", :access_token => @client.access_token}). to_return(:body => fixture("follow_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.follow_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "follow", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.follow_user(4) status.outgoing_status.should == "requested" end end - + describe ".unfollow_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "unfollow", :access_token => @client.access_token}). to_return(:body => fixture("unfollow_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.unfollow_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "unfollow", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.unfollow_user(4) status.outgoing_status.should == "none" end end - + describe ".block_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "block", :access_token => @client.access_token}). to_return(:body => fixture("block_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.block_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "block", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.block_user(4) status.outgoing_status.should == "none" end end - + describe ".unblock_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "unblock", :access_token => @client.access_token}). to_return(:body => fixture("unblock_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.unblock_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "unblock", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.unblock_user(4) status.outgoing_status.should == "none" end end - + describe ".approve_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "approve", :access_token => @client.access_token}). to_return(:body => fixture("approve_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.approve_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "approve", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.approve_user(4) status.outgoing_status.should == "follows" end end - + describe ".deny_user" do - + before do stub_post("users/4/relationship.#{format}"). with(:body => {:action => "deny", :access_token => @client.access_token}). to_return(:body => fixture("deny_user.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8"}) end - + it "should get the correct resource" do @client.deny_user(4) a_post("users/4/relationship.#{format}"). with(:body => {:action => "deny", :access_token => @client.access_token}). should have_been_made end - + it "should return a relationship status response" do status = @client.deny_user(4) status.outgoing_status.should == "none" diff --git a/spec/instagram/response_spec.rb b/spec/instagram/response_spec.rb new file mode 100644 index 00000000..e6c57388 --- /dev/null +++ b/spec/instagram/response_spec.rb @@ -0,0 +1,28 @@ +require File.expand_path('../../spec_helper', __FILE__) + +describe Instagram::Response do + Instagram::Configuration::VALID_FORMATS.each do |format| + context ".new(:format => '#{format}')" do + before do + @client = Instagram::Client.new(:format => format, :client_id => 'CID', :client_secret => 'CS', :access_token => 'AT') + end + + context 'to a standard request' do + before do + stub_get("users/4.#{format}"). + with(:query => {:access_token => @client.access_token}). + to_return(:body => fixture("mikeyk.#{format}"), :headers => {:content_type => "application/#{format}; charset=utf-8", + 'x-ratelimit-limit' => '5000', + 'x-ratelimit-remaining' => '4999'}) + end + + it 'should provide rate limit information on every object returned' do + user = @client.user(4) + user.ratelimit.should_not be_nil + user.ratelimit.limit.should == 5000 + user.ratelimit.remaining.should == 4999 + end + end + end + end +end \ No newline at end of file