bitly-oauth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +154 -0
- data/LICENSE +20 -0
- data/README.md +87 -0
- data/README.rdoc +35 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/lib/bitly_oauth.rb +28 -0
- data/lib/bitly_oauth/access_token.rb +37 -0
- data/lib/bitly_oauth/client.rb +149 -0
- data/lib/bitly_oauth/country.rb +10 -0
- data/lib/bitly_oauth/day.rb +12 -0
- data/lib/bitly_oauth/error.rb +15 -0
- data/lib/bitly_oauth/lib/core_ext/hash.rb +27 -0
- data/lib/bitly_oauth/lib/core_ext/string.rb +5 -0
- data/lib/bitly_oauth/missing_url.rb +12 -0
- data/lib/bitly_oauth/realtime_link.rb +16 -0
- data/lib/bitly_oauth/referrer.rb +12 -0
- data/lib/bitly_oauth/referring_domain.rb +11 -0
- data/lib/bitly_oauth/response.rb +39 -0
- data/lib/bitly_oauth/url.rb +118 -0
- data/lib/bitly_oauth/user.rb +104 -0
- data/test/fixtures/9uX1TE.json +1 -0
- data/test/fixtures/9uX1TEclicks.json +1 -0
- data/test/fixtures/9uX1TEclicks2.json +1 -0
- data/test/fixtures/9uX1TEinfo.json +1 -0
- data/test/fixtures/9uX1TEinfo2.json +1 -0
- data/test/fixtures/auth_fail.json +1 -0
- data/test/fixtures/auth_success.json +1 -0
- data/test/fixtures/betaworks.json +1 -0
- data/test/fixtures/betaworks2.json +1 -0
- data/test/fixtures/betaworks_jmp.json +1 -0
- data/test/fixtures/betaworks_other_user.json +1 -0
- data/test/fixtures/bitly9uX1TE.json +1 -0
- data/test/fixtures/bitly_pro_domain.json +1 -0
- data/test/fixtures/clicks_by_day.json +1 -0
- data/test/fixtures/clicks_by_day1.json +1 -0
- data/test/fixtures/clicks_by_day2.json +1 -0
- data/test/fixtures/clicks_by_minute1_url.json +1 -0
- data/test/fixtures/clicks_by_minute2_url.json +1 -0
- data/test/fixtures/clicks_by_minute_hash.json +1 -0
- data/test/fixtures/clicks_by_minute_hashes.json +1 -0
- data/test/fixtures/country_hash.json +1 -0
- data/test/fixtures/country_hash2.json +1 -0
- data/test/fixtures/country_url.json +1 -0
- data/test/fixtures/failure.json +1 -0
- data/test/fixtures/invalid_bitly_pro_domain.json +1 -0
- data/test/fixtures/invalid_credentials.json +1 -0
- data/test/fixtures/invalid_domain.json +1 -0
- data/test/fixtures/invalid_user.json +1 -0
- data/test/fixtures/invalid_x_api_key.json +1 -0
- data/test/fixtures/lookup_multiple_url.json +1 -0
- data/test/fixtures/lookup_not_real_url.json +1 -0
- data/test/fixtures/lookup_single_url.json +1 -0
- data/test/fixtures/missing_hash.json +1 -0
- data/test/fixtures/multiple_info.json +1 -0
- data/test/fixtures/multiple_url_click.json +1 -0
- data/test/fixtures/multiple_urls.json +1 -0
- data/test/fixtures/not_bitly_pro_domain.json +1 -0
- data/test/fixtures/not_found_info.json +1 -0
- data/test/fixtures/referrer_hash.json +1 -0
- data/test/fixtures/referrer_hash2.json +1 -0
- data/test/fixtures/referrer_url.json +1 -0
- data/test/fixtures/success.json +1 -0
- data/test/fixtures/url_info.json +1 -0
- data/test/fixtures/user_clicks.json +32 -0
- data/test/fixtures/user_countries.json +60 -0
- data/test/fixtures/user_realtime_links.json +15 -0
- data/test/fixtures/user_referrers.json +1 -0
- data/test/fixtures/valid_user.json +1 -0
- data/test/integration/strategy/old_test_api_key.rb +20 -0
- data/test/integration/test_client.rb +709 -0
- data/test/integration/test_user.rb +97 -0
- data/test/test_helper.rb +54 -0
- data/test/unit/core_ext/test_hash.rb +69 -0
- data/test/unit/core_ext/test_string.rb +14 -0
- data/test/unit/test_bitly_oauth.rb +19 -0
- data/test/unit/test_client.rb +87 -0
- data/test/unit/test_country.rb +19 -0
- data/test/unit/test_day.rb +22 -0
- data/test/unit/test_error.rb +11 -0
- data/test/unit/test_missing.rb +34 -0
- data/test/unit/test_realtime_link.rb +30 -0
- data/test/unit/test_referrer.rb +19 -0
- data/test/unit/test_referring_domain.rb +21 -0
- data/test/unit/test_response.rb +86 -0
- data/test/unit/test_url.rb +156 -0
- data/test/unit/test_user.rb +17 -0
- metadata +215 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
module BitlyOAuth
|
2
|
+
|
3
|
+
# Day objects are created by the clicks_by_day method of a url
|
4
|
+
class Day
|
5
|
+
attr_reader :clicks, :day_start
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@clicks = options['clicks']
|
9
|
+
@day_start = Time.at(options['day_start']) if options['day_start']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BitlyOAuth
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader :code, :response
|
4
|
+
|
5
|
+
alias :msg :message
|
6
|
+
|
7
|
+
def initialize(response)
|
8
|
+
@response = response
|
9
|
+
@message = response.reason
|
10
|
+
@code = response.status
|
11
|
+
|
12
|
+
super("#{@message} - '#{@code}'")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
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,12 @@
|
|
1
|
+
module BitlyOAuth
|
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 BitlyOAuth
|
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 BitlyOAuth::Url from the data
|
12
|
+
def create_url(client)
|
13
|
+
BitlyOAuth::Url.new(client, 'user_clicks' => clicks, 'user_hash' => user_hash)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module BitlyOAuth
|
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 BitlyOAuth
|
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,118 @@
|
|
1
|
+
module BitlyOAuth
|
2
|
+
|
3
|
+
class Url
|
4
|
+
attr_reader :short_url, :long_url, :user_hash, :global_hash, :referrers, :countries
|
5
|
+
|
6
|
+
# Initialize with a bitly client and optional hash to fill in the details for the url.
|
7
|
+
def initialize(client, options = {})
|
8
|
+
@client = client
|
9
|
+
@title = options['title'] || '' if options.key?('title')
|
10
|
+
@new_hash = (options['new_hash'] == 1)
|
11
|
+
@long_url = options['long_url']
|
12
|
+
@user_hash = options['hash'] || options['user_hash']
|
13
|
+
@short_url = options['url'] || options['short_url'] || "http://bit.ly/#{@user_hash}"
|
14
|
+
@created_by = options['created_by']
|
15
|
+
@global_hash = options['global_hash']
|
16
|
+
@user_clicks = options['user_clicks']
|
17
|
+
@global_clicks = options['global_clicks']
|
18
|
+
|
19
|
+
@referrers = options['referrers'].map{|referrer| BitlyOAuth::Referrer.new(referrer) } if options['referrers']
|
20
|
+
@countries = options['countries'].map{|country| BitlyOAuth::Country.new(country) } if options['countries']
|
21
|
+
|
22
|
+
if options['clicks'] && options['clicks'][0].is_a?(Hash)
|
23
|
+
@clicks_by_day = options['clicks'].map{|day| BitlyOAuth::Day.new(day)}
|
24
|
+
else
|
25
|
+
@clicks_by_minute = options['clicks']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns true if the user hash was created first for this call
|
30
|
+
def new_hash?
|
31
|
+
@new_hash
|
32
|
+
end
|
33
|
+
|
34
|
+
# If the url already has click statistics, returns the user clicks.
|
35
|
+
# IF there are no click statistics or <tt>:force => true</tt> is passed,
|
36
|
+
# updates the stats and returns the user clicks
|
37
|
+
def user_clicks(options={})
|
38
|
+
update_clicks_data if @user_clicks.nil? || options[:force]
|
39
|
+
@user_clicks
|
40
|
+
end
|
41
|
+
|
42
|
+
# If the url already has click statistics, returns the global clicks.
|
43
|
+
# IF there are no click statistics or <tt>:force => true</tt> is passed,
|
44
|
+
# updates the stats and returns the global clicks
|
45
|
+
def global_clicks(options={})
|
46
|
+
update_clicks_data if @global_clicks.nil? || options[:force]
|
47
|
+
@global_clicks
|
48
|
+
end
|
49
|
+
|
50
|
+
# If the url already has the title, return it.
|
51
|
+
# IF there is no title or <tt>:force => true</tt> is passed,
|
52
|
+
# updates the info and returns the title
|
53
|
+
def title(options={})
|
54
|
+
update_info if @title.nil? || options[:force]
|
55
|
+
@title
|
56
|
+
end
|
57
|
+
|
58
|
+
# If the url already has the creator, return it.
|
59
|
+
# IF there is no creator or <tt>:force => true</tt> is passed,
|
60
|
+
# updates the info and returns the creator
|
61
|
+
def created_by(options={})
|
62
|
+
update_info if @created_by.nil? || options[:force]
|
63
|
+
@created_by
|
64
|
+
end
|
65
|
+
|
66
|
+
# If the url already has referrer data, return it.
|
67
|
+
# IF there is no referrer or <tt>:force => true</tt> is passed,
|
68
|
+
# updates the referrers and returns them
|
69
|
+
def referrers(options={})
|
70
|
+
if @referrers.nil? || options[:force]
|
71
|
+
full_url = @client.referrers(@user_hash || @short_url)
|
72
|
+
@referrers = full_url.referrers
|
73
|
+
end
|
74
|
+
@referrers
|
75
|
+
end
|
76
|
+
|
77
|
+
# If the url already has country data, return it.
|
78
|
+
# IF there is no country or <tt>:force => true</tt> is passed,
|
79
|
+
# updates the countries and returns them
|
80
|
+
def countries(options={})
|
81
|
+
if @countries.nil? || options[:force]
|
82
|
+
full_url = @client.countries(@user_hash || @short_url)
|
83
|
+
@countries = full_url.countries
|
84
|
+
end
|
85
|
+
@countries
|
86
|
+
end
|
87
|
+
|
88
|
+
def clicks_by_minute(options={})
|
89
|
+
if @clicks_by_minute.nil? || options[:force]
|
90
|
+
full_url = @client.clicks_by_minute(@user_hash || @short_url)
|
91
|
+
@clicks_by_minute = full_url.clicks_by_minute
|
92
|
+
end
|
93
|
+
@clicks_by_minute
|
94
|
+
end
|
95
|
+
|
96
|
+
def clicks_by_day(options={})
|
97
|
+
if @clicks_by_day.nil? || options[:force]
|
98
|
+
full_url = @client.clicks_by_day(@user_hash || @short_url)
|
99
|
+
@clicks_by_day = full_url.clicks_by_day
|
100
|
+
end
|
101
|
+
@clicks_by_day
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def update_clicks_data
|
107
|
+
full_url = @client.clicks(@user_hash || @short_url)
|
108
|
+
@global_clicks = full_url.global_clicks
|
109
|
+
@user_clicks = full_url.user_clicks
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_info
|
113
|
+
full_url = @client.info(@user_hash || @short_url)
|
114
|
+
@created_by = full_url.created_by
|
115
|
+
@title = full_url.title
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module BitlyOAuth
|
2
|
+
|
3
|
+
# A user requires a BitlyOAuth::AccessToken. The flow is as follows:
|
4
|
+
#
|
5
|
+
# client = BitlyOAuth::Client.new(consumer_token, consumer_secret)
|
6
|
+
# client.authorize_url(redirect_url)
|
7
|
+
# #=> "https://bitly.com/oauth/authorize?client_id=id&type=code&redirect_uri=http%3A%2F%2Ftest.local%2Fbitly-oauth%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
|
+
# token = o.get_access_token_from_code(params[:code], redirect_url)
|
13
|
+
# #=> #<BitlyOAuth::AccessToken ...>
|
14
|
+
#
|
15
|
+
# Then use that access token to create your user object.
|
16
|
+
#
|
17
|
+
# user = BitlyOAuth::User.new(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, BitlyOAuth::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, BitlyOAuth::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| BitlyOAuth::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 ||= begin
|
75
|
+
client = BitlyOAuth::Client.new(@access_token.client.id, @access_token.client.secret)
|
76
|
+
client.set_access_token_from_token(@access_token.token)
|
77
|
+
client
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def get_method(method, klass, options)
|
84
|
+
result = get(method, options)
|
85
|
+
result[method.to_s].map do |rs|
|
86
|
+
rs.map do |obj|
|
87
|
+
klass.new(obj)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_clicks(options={})
|
93
|
+
if @clicks.nil? || options.delete(:force)
|
94
|
+
result = get(:clicks, options)
|
95
|
+
@clicks = result['clicks'].map { |rs| BitlyOAuth::Day.new(rs) }
|
96
|
+
@total_clicks = result['total_clicks']
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def get(method, options)
|
101
|
+
@access_token.get("user/#{method}", options)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -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"}
|