bitlyr 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/History.txt +146 -0
  2. data/LICENSE +20 -0
  3. data/README.md +97 -0
  4. data/README.rdoc +37 -0
  5. data/Rakefile +43 -0
  6. data/VERSION +1 -0
  7. data/bitlyr.gemspec +154 -0
  8. data/lib/bitlyr/client.rb +153 -0
  9. data/lib/bitlyr/country.rb +10 -0
  10. data/lib/bitlyr/day.rb +12 -0
  11. data/lib/bitlyr/error.rb +13 -0
  12. data/lib/bitlyr/lib/core_ext/hash.rb +27 -0
  13. data/lib/bitlyr/lib/core_ext/string.rb +5 -0
  14. data/lib/bitlyr/missing_url.rb +12 -0
  15. data/lib/bitlyr/realtime_link.rb +16 -0
  16. data/lib/bitlyr/referrer.rb +12 -0
  17. data/lib/bitlyr/response.rb +39 -0
  18. data/lib/bitlyr/strategy/access_token.rb +26 -0
  19. data/lib/bitlyr/strategy/api_key.rb +33 -0
  20. data/lib/bitlyr/strategy/base.rb +26 -0
  21. data/lib/bitlyr/strategy/oauth.rb +50 -0
  22. data/lib/bitlyr/url.rb +124 -0
  23. data/lib/bitlyr/user.rb +100 -0
  24. data/lib/bitlyr.rb +39 -0
  25. data/test/fixtures/9uX1TE.json +1 -0
  26. data/test/fixtures/9uX1TEclicks.json +1 -0
  27. data/test/fixtures/9uX1TEclicks2.json +1 -0
  28. data/test/fixtures/9uX1TEinfo.json +1 -0
  29. data/test/fixtures/9uX1TEinfo2.json +1 -0
  30. data/test/fixtures/auth_fail.json +1 -0
  31. data/test/fixtures/auth_success.json +1 -0
  32. data/test/fixtures/betaworks.json +1 -0
  33. data/test/fixtures/betaworks2.json +1 -0
  34. data/test/fixtures/betaworks_jmp.json +1 -0
  35. data/test/fixtures/betaworks_other_user.json +1 -0
  36. data/test/fixtures/bitly9uX1TE.json +1 -0
  37. data/test/fixtures/bitly_pro_domain.json +1 -0
  38. data/test/fixtures/clicks_by_day.json +1 -0
  39. data/test/fixtures/clicks_by_day1.json +1 -0
  40. data/test/fixtures/clicks_by_day2.json +1 -0
  41. data/test/fixtures/clicks_by_minute1_url.json +1 -0
  42. data/test/fixtures/clicks_by_minute2_url.json +1 -0
  43. data/test/fixtures/clicks_by_minute_hash.json +1 -0
  44. data/test/fixtures/clicks_by_minute_hashes.json +1 -0
  45. data/test/fixtures/country_hash.json +1 -0
  46. data/test/fixtures/country_hash2.json +1 -0
  47. data/test/fixtures/country_url.json +1 -0
  48. data/test/fixtures/failure.json +1 -0
  49. data/test/fixtures/invalid_bitly_pro_domain.json +1 -0
  50. data/test/fixtures/invalid_credentials.json +1 -0
  51. data/test/fixtures/invalid_domain.json +1 -0
  52. data/test/fixtures/invalid_user.json +1 -0
  53. data/test/fixtures/invalid_x_api_key.json +1 -0
  54. data/test/fixtures/lookup_multiple_url.json +1 -0
  55. data/test/fixtures/lookup_not_real_url.json +1 -0
  56. data/test/fixtures/lookup_single_url.json +1 -0
  57. data/test/fixtures/missing_hash.json +1 -0
  58. data/test/fixtures/multiple_info.json +1 -0
  59. data/test/fixtures/multiple_url_click.json +1 -0
  60. data/test/fixtures/multiple_urls.json +1 -0
  61. data/test/fixtures/not_bitly_pro_domain.json +1 -0
  62. data/test/fixtures/not_found_info.json +1 -0
  63. data/test/fixtures/referrer_hash.json +1 -0
  64. data/test/fixtures/referrer_hash2.json +1 -0
  65. data/test/fixtures/referrer_url.json +1 -0
  66. data/test/fixtures/success.json +1 -0
  67. data/test/fixtures/url_info.json +1 -0
  68. data/test/fixtures/user_clicks.json +32 -0
  69. data/test/fixtures/user_countries.json +60 -0
  70. data/test/fixtures/user_realtime_links.json +15 -0
  71. data/test/fixtures/user_referrers.json +1 -0
  72. data/test/fixtures/valid_user.json +1 -0
  73. data/test/integration/strategy/test_api_key.rb +20 -0
  74. data/test/integration/strategy/test_oauth.rb +52 -0
  75. data/test/integration/test_client.rb +1415 -0
  76. data/test/integration/test_user.rb +97 -0
  77. data/test/test_helper.rb +54 -0
  78. data/test/unit/core_ext/test_hash.rb +69 -0
  79. data/test/unit/core_ext/test_string.rb +14 -0
  80. data/test/unit/strategy/test_access_token.rb +14 -0
  81. data/test/unit/strategy/test_api_key.rb +11 -0
  82. data/test/unit/strategy/test_base.rb +71 -0
  83. data/test/unit/strategy/test_oauth.rb +32 -0
  84. data/test/unit/test_bitly.rb +43 -0
  85. data/test/unit/test_client.rb +21 -0
  86. data/test/unit/test_country.rb +20 -0
  87. data/test/unit/test_day.rb +22 -0
  88. data/test/unit/test_error.rb +11 -0
  89. data/test/unit/test_missing.rb +34 -0
  90. data/test/unit/test_realtime_link.rb +30 -0
  91. data/test/unit/test_referrer.rb +20 -0
  92. data/test/unit/test_response.rb +86 -0
  93. data/test/unit/test_url.rb +155 -0
  94. data/test/unit/test_user.rb +17 -0
  95. metadata +233 -0
@@ -0,0 +1,13 @@
1
+ class BitlyrError < StandardError
2
+ attr_reader :code, :response
3
+
4
+ alias :msg :message
5
+
6
+ def initialize(response)
7
+ @response = response
8
+ @message = response.reason
9
+ @code = response.status
10
+
11
+ super("#{@message} - '#{@code}'")
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ class Hash
2
+ def to_query
3
+ map {|k, v|"#{k}=#{v}"}.sort * '&'
4
+ end
5
+
6
+ def stringify_keys!
7
+ keys.each do |key|
8
+ self[key.to_s] = delete(key)
9
+ end
10
+ self
11
+ end
12
+
13
+ def stringify_keys
14
+ dup.stringify_keys!
15
+ end
16
+
17
+ def symbolize_keys!
18
+ keys.each do |key|
19
+ self[(key.to_sym rescue key) || key] = delete(key)
20
+ end
21
+ self
22
+ end
23
+
24
+ def symbolize_keys
25
+ dup.symbolize_keys!
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_a
3
+ [ self ]
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module Bitlyr
2
+ class MissingUrl
3
+ attr_accessor :short_url, :user_hash, :long_url, :error
4
+
5
+ def initialize(options={})
6
+ @error = options['error']
7
+ @long_url = options['long_url']
8
+ @short_url = options['short_url']
9
+ @user_hash = options['hash']
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Bitlyr
2
+ # Day objects are created by the realtime_links method of a user
3
+ class RealtimeLink
4
+ attr_reader :clicks, :user_hash
5
+
6
+ def initialize(options = {})
7
+ @clicks = options['clicks']
8
+ @user_hash = options['user_hash']
9
+ end
10
+
11
+ # A convenience method to create a Bitlyr::Url from the data
12
+ def create_url(client)
13
+ Bitlyr::Url.new(client, 'user_clicks' => clicks, 'user_hash' => user_hash)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Bitlyr
2
+ class Referrer
3
+ attr_reader :clicks, :referrer, :referrer_app, :url
4
+
5
+ def initialize(options)
6
+ @url = options['url']
7
+ @clicks = options['clicks']
8
+ @referrer = options['referrer']
9
+ @referrer_app = options['referrer_app']
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ module Bitlyr
2
+ class Response
3
+ REASONS = { "OK" => "OK",
4
+ "INVALID_URI" => "Invalid URI" }.freeze
5
+
6
+ def initialize(response)
7
+ @response = response
8
+ end
9
+
10
+ def success?
11
+ parsed['status_code'] == 200
12
+ end
13
+
14
+ def status
15
+ parsed['status_code']
16
+ end
17
+
18
+ def reason
19
+ status = parsed['status_txt']
20
+ REASONS[ status ] || status.split('_').map(&:capitalize) * ' '
21
+ end
22
+
23
+ def body
24
+ parsed['data']
25
+ end
26
+
27
+ private
28
+ def parsed
29
+ case @response
30
+ when OAuth2::Response
31
+ @response.parsed
32
+ when HTTParty::Response
33
+ @response.parsed_response
34
+ else
35
+ raise "Unsupported Response type: #{@response.class}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Bitlyr
2
+ module Strategy
3
+ class AccessToken < Base
4
+ extend Forwardable
5
+ delegate [ :client, :[] ] => :access_token
6
+
7
+ def initialize(access_token)
8
+ @access_token = access_token
9
+ end
10
+
11
+ private
12
+ # Make a request from the access token
13
+ def run_request(verb, method, options={})
14
+ access_token.send(verb, method, :params => authorization_params.merge(options), :parse => :json)
15
+ end
16
+
17
+ def access_token
18
+ @access_token
19
+ end
20
+
21
+ def authorization_params
22
+ { :access_token => access_token.token }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module Bitlyr
2
+ module Strategy
3
+ class ApiKey < Base
4
+ include HTTParty
5
+ base_uri 'http://api.bit.ly/v3/'
6
+ query_string_normalizer proc { |query|
7
+ query.map do |key, value|
8
+ case value
9
+ when Array
10
+ value.map { |v| "#{key}=#{CGI.escape( v.to_s )}" }
11
+ else
12
+ "#{key}=#{CGI.escape( value.to_s )}"
13
+ end
14
+ end.compact.join('&')
15
+ }
16
+
17
+ def initialize(login, api_key)
18
+ @login = login
19
+ @api_key = api_key
20
+ end
21
+
22
+ private
23
+ # Make a request using the login and apiKey
24
+ def run_request(verb, method, options={})
25
+ self.class.send(verb, "/#{method}", :query => authorization_params.merge(options))
26
+ end
27
+
28
+ def authorization_params
29
+ { :login => @login, :apiKey => @api_key }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ module Bitlyr
2
+ module Strategy
3
+ class Base
4
+ def request(*args)
5
+ response = Bitlyr::Response.new(run_request(*args))
6
+ if response.success?
7
+ response.body
8
+ else
9
+ raise BitlyrError.new(response)
10
+ end
11
+ end
12
+
13
+ # Validates a login and api key
14
+ def validate(x_login, x_api_key)
15
+ response = request(:get, :validate, :x_login => x_login, :x_apiKey => x_api_key)
16
+ return response['valid'] == 1
17
+ end
18
+ alias :valid? :validate
19
+
20
+ private
21
+ def run_request(*args)
22
+ raise "Define this in the subclass"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ module Bitlyr
2
+ module Strategy
3
+ class OAuth < Base
4
+ extend Forwardable
5
+ delegate [ :run_request ] => :access_token
6
+
7
+ BASE_URL = 'https://api-ssl.bit.ly/v3/'
8
+
9
+ def initialize(consumer_token, consumer_secret)
10
+ @consumer_token = consumer_token
11
+ @consumer_secret = consumer_secret
12
+ end
13
+
14
+ # Get the url to redirect a user to, pass the url you want the user
15
+ # to be redirected back to.
16
+ def authorize_url(redirect_url)
17
+ client.auth_code.authorize_url(:redirect_uri => redirect_url)
18
+ end
19
+
20
+ # Get the access token. You must pass the exact same redirect_url passed
21
+ # to the authorize_url method
22
+ def get_access_token_from_code(code, redirect_url)
23
+ access_token = client.auth_code.get_token(code, :redirect_uri => redirect_url, :parse => :query)
24
+ Bitlyr::Strategy::AccessToken.new(access_token)
25
+ end
26
+
27
+ # If you already have a user token, this method gets the access token
28
+ def get_access_token_from_token(token, params={})
29
+ params.stringify_keys!
30
+ access_token = ::OAuth2::AccessToken.new(client, token, params)
31
+ Bitlyr::Strategy::AccessToken.new(access_token)
32
+ end
33
+
34
+ # If you already have a user token, this method sets the access token
35
+ def set_access_token_from_token!(token, params={})
36
+ @access_token ||= get_access_token_from_token(token, params)
37
+ end
38
+
39
+ private
40
+ # Get the OAuth 2 client
41
+ def client
42
+ @client ||= ::OAuth2::Client.new(@consumer_token, @consumer_secret, :site => BASE_URL, :token_url => '/oauth/access_token')
43
+ end
44
+
45
+ def access_token
46
+ @access_token
47
+ end
48
+ end
49
+ end
50
+ end
data/lib/bitlyr/url.rb ADDED
@@ -0,0 +1,124 @@
1
+ module Bitlyr
2
+
3
+ # Url objects should only be created by the client object as it collects the correct information
4
+ # from the API.
5
+ class Url
6
+ attr_reader :short_url, :long_url, :user_hash, :global_hash, :referrers, :countries
7
+
8
+ # Initialize with a bitly client and optional hash to fill in the details for the url.
9
+ def initialize(client, options = {})
10
+ @client = client
11
+ @title = options['title'] || '' if options.key?('title')
12
+ @new_hash = (options['new_hash'] == 1)
13
+ @long_url = options['long_url']
14
+ @user_hash = options['hash'] || options['user_hash']
15
+ @short_url = options['url'] || options['short_url'] || "http://bit.ly/#{@user_hash}"
16
+ @created_by = options['created_by']
17
+ @global_hash = options['global_hash']
18
+ @user_clicks = options['user_clicks']
19
+ @global_clicks = options['global_clicks']
20
+
21
+ @referrers = options['referrers'].map{|referrer| Bitlyr::Referrer.new(referrer) } if options['referrers']
22
+ @countries = options['countries'].map{|country| Bitlyr::Country.new(country) } if options['countries']
23
+
24
+ if options['clicks'] && options['clicks'][0].is_a?(Hash)
25
+ @clicks_by_day = options['clicks'].map{|day| Bitlyr::Day.new(day)}
26
+ else
27
+ @clicks_by_minute = options['clicks']
28
+ end
29
+ end
30
+
31
+ # Returns true if the user hash was created first for this call
32
+ def new_hash?
33
+ @new_hash
34
+ end
35
+
36
+ # If the url already has click statistics, returns the user clicks.
37
+ # IF there are no click statistics or <tt>:force => true</tt> is passed,
38
+ # updates the stats and returns the user clicks
39
+ def user_clicks(options={})
40
+ update_clicks_data if @user_clicks.nil? || options[:force]
41
+ @user_clicks
42
+ end
43
+
44
+ # If the url already has click statistics, returns the global clicks.
45
+ # IF there are no click statistics or <tt>:force => true</tt> is passed,
46
+ # updates the stats and returns the global clicks
47
+ def global_clicks(options={})
48
+ update_clicks_data if @global_clicks.nil? || options[:force]
49
+ @global_clicks
50
+ end
51
+
52
+ # If the url already has the title, return it.
53
+ # IF there is no title or <tt>:force => true</tt> is passed,
54
+ # updates the info and returns the title
55
+ def title(options={})
56
+ update_info if @title.nil? || options[:force]
57
+ @title
58
+ end
59
+
60
+ # If the url already has the creator, return it.
61
+ # IF there is no creator or <tt>:force => true</tt> is passed,
62
+ # updates the info and returns the creator
63
+ def created_by(options={})
64
+ update_info if @created_by.nil? || options[:force]
65
+ @created_by
66
+ end
67
+
68
+ # If the url already has referrer data, return it.
69
+ # IF there is no referrer or <tt>:force => true</tt> is passed,
70
+ # updates the referrers and returns them
71
+ def referrers(options={})
72
+ update_referrers if @referrers.nil? || options[:force]
73
+ @referrers
74
+ end
75
+
76
+ # If the url already has country data, return it.
77
+ # IF there is no country or <tt>:force => true</tt> is passed,
78
+ # updates the countries and returns them
79
+ def countries(options={})
80
+ update_countries if @countries.nil? || options[:force]
81
+ @countries
82
+ end
83
+
84
+ def clicks_by_minute(options={})
85
+ if @clicks_by_minute.nil? || options[:force]
86
+ full_url = @client.clicks_by_minute(@user_hash || @short_url)
87
+ @clicks_by_minute = full_url.clicks_by_minute
88
+ end
89
+ @clicks_by_minute
90
+ end
91
+
92
+ def clicks_by_day(options={})
93
+ if @clicks_by_day.nil? || options[:force]
94
+ full_url = @client.clicks_by_day(@user_hash || @short_url)
95
+ @clicks_by_day = full_url.clicks_by_day
96
+ end
97
+ @clicks_by_day
98
+ end
99
+
100
+ private
101
+
102
+ def update_clicks_data
103
+ full_url = @client.clicks(@user_hash || @short_url)
104
+ @global_clicks = full_url.global_clicks
105
+ @user_clicks = full_url.user_clicks
106
+ end
107
+
108
+ def update_info
109
+ full_url = @client.info(@user_hash || @short_url)
110
+ @created_by = full_url.created_by
111
+ @title = full_url.title
112
+ end
113
+
114
+ def update_referrers
115
+ full_url = @client.referrers(@user_hash || @short_url)
116
+ @referrers = full_url.referrers
117
+ end
118
+
119
+ def update_countries
120
+ full_url = @client.countries(@user_hash || @short_url)
121
+ @countries = full_url.countries
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,100 @@
1
+ module Bitlyr
2
+
3
+ # A user requires an oauth access token. The flow is as follows:
4
+ #
5
+ # o = Bitlyr::Strategy::OAuth.new(consumer_token, consumer_secret)
6
+ # o.authorize_url(redirect_url)
7
+ # #=> "https://bit.ly/oauth/authorize?client_id=#{consumer_token}&type=web_server&redirect_uri=http%3A%2F%2Ftest.local%2Fbitlyr%2Fauth"
8
+ # Redirect your users to this url, when they authorize your application
9
+ # they will be redirected to the url you provided with a code parameter.
10
+ # Use that parameter, and the exact same redirect url as follows:
11
+ #
12
+ # o.get_access_token_from_code(params[:code], redirect_url)
13
+ # #=> #<Bitlyr::AccessToken ...>
14
+ #
15
+ # Then use that access token to create your user object.
16
+ #
17
+ # u=Bitlyr::User.new(o.access_token)
18
+ class User
19
+
20
+ def initialize(access_token)
21
+ @access_token = access_token
22
+ end
23
+
24
+ # OAuth 2 endpoint that provides a list of top referrers (up to 500 per
25
+ # day) for a given user’s bit.ly links, and the number of clicks per referrer.
26
+ #
27
+ # http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/user/referrers
28
+ def referrers(options={})
29
+ if @referrers.nil? || options.delete(:force)
30
+ @referrers = get_method(:referrers, Bitlyr::Referrer, options)
31
+ end
32
+ @referrers
33
+ end
34
+
35
+ # OAuth 2 endpoint that provides a list of countries from which clicks
36
+ # on a given user’s bit.ly links are originating, and the number of clicks per country.
37
+ #
38
+ # http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/user/countries
39
+ def countries(options={})
40
+ if @countries.nil? || options.delete(:force)
41
+ @countries = get_method(:countries, Bitlyr::Country, options)
42
+ end
43
+ @countries
44
+ end
45
+
46
+ # OAuth 2 endpoint that provides a given user’s 100 most popular links
47
+ # based on click traffic in the past hour, and the number of clicks per link.
48
+ #
49
+ # http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/user/realtime_links
50
+ def realtime_links(options={})
51
+ if @realtime_links.nil? || options.delete(:force)
52
+ result = get(:realtime_links, options)
53
+ @realtime_links = result['realtime_links'].map { |rs| Bitlyr::RealtimeLink.new(rs) }
54
+ end
55
+ @realtime_links
56
+ end
57
+
58
+ # OAuth 2 endpoint that provides the total clicks per day on a user’s bit.ly links.
59
+ #
60
+ # http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/user/clicks
61
+ def clicks(options={})
62
+ get_clicks(options)
63
+ @clicks
64
+ end
65
+
66
+ # Displays the total clicks returned from the clicks method.
67
+ def total_clicks(options={})
68
+ get_clicks(options)
69
+ @total_clicks
70
+ end
71
+
72
+ # Returns a Bitly Client using the credentials of the user.
73
+ def client
74
+ @client ||= Bitlyr::Client.new(@access_token)
75
+ end
76
+
77
+ private
78
+
79
+ def get_method(method, klass, options)
80
+ result = get(method, options)
81
+ result[method.to_s].map do |rs|
82
+ rs.map do |obj|
83
+ klass.new(obj)
84
+ end
85
+ end
86
+ end
87
+
88
+ def get_clicks(options={})
89
+ if @clicks.nil? || options.delete(:force)
90
+ result = get(:clicks, options)
91
+ @clicks = result['clicks'].map { |rs| Bitlyr::Day.new(rs) }
92
+ @total_clicks = result['total_clicks']
93
+ end
94
+ end
95
+
96
+ def get(method, options)
97
+ @access_token.request(:get, "user/#{method}", options)
98
+ end
99
+ end
100
+ end
data/lib/bitlyr.rb ADDED
@@ -0,0 +1,39 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'httparty'
4
+ require 'oauth2'
5
+ require 'cgi'
6
+ require 'forwardable'
7
+
8
+ module Bitlyr
9
+ def self.new(params = {})
10
+ params.symbolize_keys!
11
+ if params.key?(:client_id) && params.key?(:client_secret)
12
+ strategy = Bitlyr::Strategy::OAuth.new(params[:client_id], params[:client_secret])
13
+ strategy.get_access_token_from_token(params[:token]) if params[:token]
14
+ Bitlyr::Client.new strategy
15
+ elsif params.key?(:login) && params.key?(:api_key)
16
+ Bitlyr::Client.new Bitlyr::Strategy::ApiKey.new(params[:login], params[:api_key])
17
+ else
18
+ raise "requires a login and apiKey or client id and client secret"
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'bitlyr/client'
24
+ require 'bitlyr/country'
25
+ require 'bitlyr/day'
26
+ require 'bitlyr/error'
27
+ require 'bitlyr/missing_url'
28
+ require 'bitlyr/realtime_link'
29
+ require 'bitlyr/referrer'
30
+ require 'bitlyr/response'
31
+ require 'bitlyr/url'
32
+ require 'bitlyr/user'
33
+ require 'bitlyr/strategy/base'
34
+ require 'bitlyr/strategy/access_token'
35
+ require 'bitlyr/strategy/api_key'
36
+ require 'bitlyr/strategy/oauth'
37
+
38
+ require 'bitlyr/lib/core_ext/hash'
39
+ require 'bitlyr/lib/core_ext/string'
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "expand": [ { "hash": "9uX1TE", "long_url": "http:\/\/betaworks.com\/", "user_hash": "9uX1TE", "global_hash": "18H1ET" } ] } }
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks": [{"user_clicks": 0, "global_hash": "18H1ET", "hash": "9uX1TE", "user_hash": "9uX1TE", "global_clicks": 81}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks": [{"user_clicks": 1, "global_hash": "18H1ET", "hash": "9uX1TE", "user_hash": "9uX1TE", "global_clicks": 82}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"info": [{"global_hash": "18H1ET", "hash": "9uX1TE", "user_hash": "9uX1TE", "created_by": "philnash", "title": "A title"}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"info": [{"global_hash": "18H1ET", "hash": "9uX1TE", "user_hash": "9uX1TE", "created_by": "philnash2", "title": "A New Title"}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"data":{"authenticate":{"successful": false}},"status_code": 200,"status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"data":{"authenticate":{"api_key": "R_0da49e0a9118ff35f52f629d2d71bf07","successful": true,"username": "bitlyapidemo"}},"status_code": 200,"status_txt": "OK"}
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "long_url": "http:\/\/betaworks.com\/", "url": "http:\/\/bit.ly\/9uX1TE", "hash": "9uX1TE", "global_hash": "18H1ET", "new_hash": 1 } }
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "long_url": "http:\/\/betaworks.com\/", "url": "http:\/\/bit.ly\/9uX1TE", "hash": "9uX1TE", "global_hash": "18H1ET", "new_hash": 0 } }
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "long_url": "http:\/\/betaworks.com\/", "url": "http:\/\/j.mp\/9uX1TE", "hash": "9uX1TE", "global_hash": "18H1ET", "new_hash": 0 } }
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "long_url": "http:\/\/betaworks.com\/", "url": "http:\/\/bit.ly\/cWJlxM", "hash": "cWJlxM", "global_hash": "18H1ET", "new_hash": 1 } }
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "expand": [ { "short_url": "http:\/\/bit.ly\/9uX1TE", "long_url": "http:\/\/betaworks.com\/", "user_hash": "9uX1TE", "global_hash": "18H1ET" } ] } }
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"domain": "nyti.ms", "bitly_pro_domain": true}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_day": [{"global_hash": "9DguyN", "hash": "9DguyN", "user_hash": "9DguyN", "clicks": [{"clicks": 1, "day_start": 1290488400}, {"clicks": 0, "day_start": 1290402000}, {"clicks": 0, "day_start": 1290315600}, {"clicks": 1, "day_start": 1290229200}, {"clicks": 0, "day_start": 1290142800}, {"clicks": 0, "day_start": 1290056400}, {"clicks": 0, "day_start": 1289970000}]}, {"global_hash": "dpC5ns", "hash": "dvxi6W", "user_hash": "dvxi6W", "clicks": [{"clicks": 1, "day_start": 1290488400}, {"clicks": 0, "day_start": 1290402000}, {"clicks": 0, "day_start": 1290315600}, {"clicks": 0, "day_start": 1290229200}, {"clicks": 0, "day_start": 1290142800}, {"clicks": 0, "day_start": 1290056400}, {"clicks": 0, "day_start": 1289970000}]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_day": [{"global_hash": "9DguyN", "hash": "9DguyN", "user_hash": "9DguyN", "clicks": [{"clicks": 1, "day_start": 1290488400}, {"clicks": 0, "day_start": 1290402000}, {"clicks": 0, "day_start": 1290315600}, {"clicks": 1, "day_start": 1290229200}, {"clicks": 0, "day_start": 1290142800}, {"clicks": 0, "day_start": 1290056400}, {"clicks": 0, "day_start": 1289970000}]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_day": [{"global_hash": "9DguyN", "hash": "9DguyN", "user_hash": "9DguyN", "clicks": [{"clicks": 2, "day_start": 1290488400}, {"clicks": 0, "day_start": 1290402000}, {"clicks": 0, "day_start": 1290315600}, {"clicks": 1, "day_start": 1290229200}, {"clicks": 0, "day_start": 1290142800}, {"clicks": 0, "day_start": 1290056400}, {"clicks": 0, "day_start": 1289970000}]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_minute": [{"short_url": "http://j.mp/9DguyN", "global_hash": "9DguyN", "user_hash": "9DguyN", "clicks": [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_minute": [{"short_url": "http://j.mp/9DguyN", "global_hash": "9DguyN", "user_hash": "9DguyN", "clicks": [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_minute": [{"global_hash": "9DguyN", "hash": "9DguyN", "user_hash": "9DguyN", "clicks": [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"clicks_by_minute": [{"global_hash": "9DguyN", "hash": "9DguyN", "user_hash": "9DguyN", "clicks": [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}, {"global_hash": "dpC5ns", "hash": "dvxi6W", "user_hash": "dvxi6W", "clicks": [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"global_hash": "djZ9g4", "hash": "djZ9g4", "user_hash": "djZ9g4", "countries": [{"country": "US", "clicks": 58}, {"country": "GB", "clicks": 14}, {"country": null, "clicks": 14}, {"country": "BR", "clicks": 6}, {"country": "CA", "clicks": 6}, {"country": "FR", "clicks": 5}, {"country": "AU", "clicks": 4}, {"country": "IN", "clicks": 4}, {"country": "DE", "clicks": 3}, {"country": "TW", "clicks": 3}, {"country": "IT", "clicks": 2}, {"country": "NO", "clicks": 2}, {"country": "PL", "clicks": 2}, {"country": "BE", "clicks": 1}, {"country": "BG", "clicks": 1}, {"country": "CI", "clicks": 1}, {"country": "CZ", "clicks": 1}, {"country": "ES", "clicks": 1}, {"country": "GR", "clicks": 1}, {"country": "HK", "clicks": 1}, {"country": "KR", "clicks": 1}, {"country": "MY", "clicks": 1}, {"country": "PH", "clicks": 1}, {"country": "PT", "clicks": 1}, {"country": "SE", "clicks": 1}, {"country": "VE", "clicks": 1}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"global_hash": "djZ9g4", "hash": "djZ9g4", "user_hash": "djZ9g4", "countries": [{"country": "US", "clicks": 59}, {"country": "GB", "clicks": 14}, {"country": null, "clicks": 14}, {"country": "BR", "clicks": 6}, {"country": "CA", "clicks": 6}, {"country": "FR", "clicks": 5}, {"country": "AU", "clicks": 4}, {"country": "IN", "clicks": 4}, {"country": "DE", "clicks": 3}, {"country": "TW", "clicks": 3}, {"country": "IT", "clicks": 2}, {"country": "NO", "clicks": 2}, {"country": "PL", "clicks": 2}, {"country": "BE", "clicks": 1}, {"country": "BG", "clicks": 1}, {"country": "CI", "clicks": 1}, {"country": "CZ", "clicks": 1}, {"country": "ES", "clicks": 1}, {"country": "GR", "clicks": 1}, {"country": "HK", "clicks": 1}, {"country": "KR", "clicks": 1}, {"country": "MY", "clicks": 1}, {"country": "PH", "clicks": 1}, {"country": "PT", "clicks": 1}, {"country": "SE", "clicks": 1}, {"country": "VE", "clicks": 1}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ {"status_code": 200, "data": {"short_url": "http://bit.ly/djZ9g4", "global_hash": "djZ9g4", "user_hash": "djZ9g4", "countries": [{"country": "US", "clicks": 58}, {"country": "GB", "clicks": 14}, {"country": null, "clicks": 14}, {"country": "BR", "clicks": 6}, {"country": "CA", "clicks": 6}, {"country": "FR", "clicks": 5}, {"country": "AU", "clicks": 4}, {"country": "IN", "clicks": 4}, {"country": "DE", "clicks": 3}, {"country": "TW", "clicks": 3}, {"country": "IT", "clicks": 2}, {"country": "NO", "clicks": 2}, {"country": "PL", "clicks": 2}, {"country": "BE", "clicks": 1}, {"country": "BG", "clicks": 1}, {"country": "CI", "clicks": 1}, {"country": "CZ", "clicks": 1}, {"country": "ES", "clicks": 1}, {"country": "GR", "clicks": 1}, {"country": "HK", "clicks": 1}, {"country": "KR", "clicks": 1}, {"country": "MY", "clicks": 1}, {"country": "PH", "clicks": 1}, {"country": "PT", "clicks": 1}, {"country": "SE", "clicks": 1}, {"country": "VE", "clicks": 1}]}, "status_txt": "OK"}
@@ -0,0 +1 @@
1
+ { "status_code": 400, "status_txt": "Bad Request", "data": { } }
@@ -0,0 +1 @@
1
+ {"status_code": 500, "data": null, "status_txt": "INVALID_DOMAIN"}
@@ -0,0 +1 @@
1
+ { "data": [ ], "status_code": 500, "status_txt": "INVALID_LOGIN" }
@@ -0,0 +1 @@
1
+ { "data": [ ], "status_code": 500, "status_txt": "INVALID_ARG_DOMAIN" }
@@ -0,0 +1 @@
1
+ { "status_code": 200, "status_txt": "OK", "data": { "valid": 0 } }
@@ -0,0 +1 @@
1
+ { "data": [ ], "status_code": 500, "status_txt": "INVALID_X_APIKEY" }