twitter_labs_api 0.4.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 471a4a8a8b2f248f11d0337240451d5b5bc2fdff5601370335f0ab080038cb0a
4
- data.tar.gz: 25f2097f036e2ba1b9431f5e4a01db6a062ea7507f05b648c85b9d3514c5d083
3
+ metadata.gz: 308afe5c20914abca1ed575f09b1e5924206034eae405886944d495fb6e4d3da
4
+ data.tar.gz: 5b931944828a477b39d0360d492c2fb6215b13ec12f8b953ac01533bcf822b44
5
5
  SHA512:
6
- metadata.gz: df432778d2baef5046f1c0d36ddd1b96f17e58414063ce3e76f15fdb9d7f78abc82327c598bc2a0e67fc3e205a430c5e5f851e1afb16691176a5722e506fe226
7
- data.tar.gz: bcad0b98629f789f004974fdc505929b7a7f42af362490a8d9bd5e3ade4389ae770e25cf1550cd46af308f3336b2c4f3018a71580e41e9f92e48d42d1aea5fca
6
+ metadata.gz: 12be24ffd5dfbc7b81b5bba6665cd264c39a8d9cbe828977b569285093b37e00036950db0a1b94c50fb287847897a6d8ba356bcb8b950c33197c4bda888a2a5a
7
+ data.tar.gz: b44d15ee5acc7a147ea3c2208c242cd45b6d5966cfbac0a2c2946b85594f73263853c4b0b45d9125567d20ffb295e33c45ae6491a2d4a0a31535a94a00b77ef7
@@ -0,0 +1,32 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
25
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: 2.7
29
+ - name: Install dependencies
30
+ run: bundle install
31
+ - name: Run tests
32
+ run: bundle exec rspec
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -1,3 +1,49 @@
1
+ # 0.7.0 - 28 August 2020
2
+
3
+ - Refactor interface for requesting custom response fields
4
+
5
+ ## Breaking Change
6
+
7
+ Heads up, the argument to request fields was previously called `tweet_fields`; it is now called `fields`.
8
+
9
+ ```ruby
10
+ api.get_tweet(id: '123455683780', fields: requested_fields)
11
+ ```
12
+
13
+ The `fields` parameter now supports multiple different data types (instead of just Tweet attributes). So for example, to request the URL of an embedded media item:
14
+
15
+ ```ruby
16
+ requested_fields = { tweet: %w[id username], media: %w[url] }
17
+
18
+ api.get_tweet(id: my_id, fields: requested_fields)
19
+ ```
20
+
21
+ # 0.6.0 - 28 July 2020
22
+
23
+ - Fix: broken dependency
24
+
25
+ # 0.5.2 - 28 July 2020
26
+
27
+ - Add `search`
28
+ - Finish `rdoc` coverage
29
+
30
+ # 0.5.1 - 28 July 2020
31
+
32
+ - Add `User-Agent` request header
33
+ - Add `hide_reply`
34
+
35
+ # 0.5.0 - 27 July 2020
36
+
37
+ - Refactor structure to prepare for adding additional API endpoints
38
+ - Add `get_users_by_username`
39
+ - Add some test coverage
40
+
41
+
42
+ # 0.4.0 - 24 July 2020
43
+
44
+ - Better exception-handling: when API returns an error, a `TwitterLabsAPI::APIError` is thrown. It has the `Net::HTTP` response as an attribute so that the error can be handled properly. See the README for an example.
45
+
46
+
1
47
  # 0.3.0 - 28 April 2020
2
48
 
3
49
  - Fix: namespace of error class
data/Gemfile CHANGED
@@ -1,7 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gemspec
3
+ group :development, :test do
4
+ gem 'amazing_print'
5
+ gem 'httplog'
6
+ gem 'irbtools'
7
+ gem 'pry'
8
+ gem 'rake'
9
+ gem 'rspec'
10
+ gem 'webmock'
11
+ end
4
12
 
5
- gem 'activesupport'
6
- gem 'httplog'
7
- gem 'pry'
13
+ gemspec
@@ -1,7 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- twitter_labs_api (0.4.0)
4
+ twitter_labs_api (0.7.0)
5
+ activesupport (~> 6.0)
6
+ httplog (~> 1.4)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
@@ -12,36 +14,121 @@ GEM
12
14
  minitest (~> 5.1)
13
15
  tzinfo (~> 1.1)
14
16
  zeitwerk (~> 2.2, >= 2.2.2)
17
+ addressable (2.7.0)
18
+ public_suffix (>= 2.0.2, < 5.0)
19
+ alias (0.2.3)
20
+ amazing_print (1.2.1)
21
+ binding.repl (3.0.0)
22
+ boson (1.3.0)
23
+ boson-more (0.3.1)
24
+ boson (>= 1.3.0)
25
+ cd (1.0.1)
26
+ clipboard (1.0.6)
15
27
  coderay (1.1.3)
16
- concurrent-ruby (1.1.6)
17
- httplog (1.3.2)
28
+ concurrent-ruby (1.1.7)
29
+ crack (0.4.3)
30
+ safe_yaml (~> 1.0.0)
31
+ debugging (1.1.1)
32
+ binding.repl (~> 3.0)
33
+ paint (>= 0.9, < 3.0)
34
+ diff-lcs (1.4.4)
35
+ every_day_irb (2.1.0)
36
+ cd (~> 1.0)
37
+ fancy_irb (1.2.1)
38
+ paint (>= 0.9, < 3.0)
39
+ unicode-display_width (~> 1.1)
40
+ ffi (1.13.1)
41
+ g (1.7.2)
42
+ hashdiff (1.0.1)
43
+ hirb (0.7.3)
44
+ httplog (1.4.3)
18
45
  rack (>= 1.0)
19
46
  rainbow (>= 2.0.0)
20
47
  i18n (1.8.5)
21
48
  concurrent-ruby (~> 1.0)
49
+ interactive_editor (0.0.11)
50
+ spoon (>= 0.0.1)
51
+ irbtools (1.7.1)
52
+ alias (~> 0.2.3)
53
+ binding.repl (~> 3.0)
54
+ boson (~> 1.3.0)
55
+ boson-more (~> 0.3.0)
56
+ clipboard (~> 1.0.5)
57
+ coderay (~> 1.1.0)
58
+ debugging (~> 1.0)
59
+ every_day_irb (>= 1.7.1)
60
+ fancy_irb (>= 0.7.3)
61
+ g (>= 1.7.2)
62
+ hirb (~> 0.7, >= 0.7.3)
63
+ interactive_editor (>= 0.0.10)
64
+ method_locator (>= 0.0.4)
65
+ method_source (>= 0.8.2)
66
+ methodfinder (~> 2.0)
67
+ ori (~> 0.1.0)
68
+ os (~> 0.9)
69
+ paint (>= 0.8.7)
70
+ ruby_engine (~> 1.0)
71
+ ruby_info (~> 1.0)
72
+ ruby_version (~> 1.0)
73
+ wirb (>= 1.0.3)
74
+ method_locator (0.0.4)
22
75
  method_source (1.0.0)
76
+ methodfinder (2.2.1)
23
77
  minitest (5.14.1)
78
+ ori (0.1.0)
79
+ os (0.9.6)
80
+ paint (2.2.0)
24
81
  pry (0.13.1)
25
82
  coderay (~> 1.1)
26
83
  method_source (~> 1.0)
84
+ public_suffix (4.0.5)
27
85
  rack (2.2.3)
28
86
  rainbow (3.0.0)
29
87
  rake (13.0.1)
88
+ rspec (3.9.0)
89
+ rspec-core (~> 3.9.0)
90
+ rspec-expectations (~> 3.9.0)
91
+ rspec-mocks (~> 3.9.0)
92
+ rspec-core (3.9.2)
93
+ rspec-support (~> 3.9.3)
94
+ rspec-expectations (3.9.2)
95
+ diff-lcs (>= 1.2.0, < 2.0)
96
+ rspec-support (~> 3.9.0)
97
+ rspec-mocks (3.9.1)
98
+ diff-lcs (>= 1.2.0, < 2.0)
99
+ rspec-support (~> 3.9.0)
100
+ rspec-support (3.9.3)
101
+ ruby_engine (1.0.1)
102
+ ruby_info (1.0.1)
103
+ ruby_version (1.0.2)
104
+ safe_yaml (1.0.5)
105
+ spoon (0.0.6)
106
+ ffi
30
107
  thread_safe (0.3.6)
31
108
  tzinfo (1.2.7)
32
109
  thread_safe (~> 0.1)
110
+ unicode-display_width (1.7.0)
111
+ webmock (3.8.3)
112
+ addressable (>= 2.3.6)
113
+ crack (>= 0.3.2)
114
+ hashdiff (>= 0.4.0, < 2.0.0)
115
+ wirb (2.2.1)
116
+ paint (>= 0.9, < 3.0)
33
117
  zeitwerk (2.4.0)
34
118
 
35
119
  PLATFORMS
36
120
  ruby
37
121
 
38
122
  DEPENDENCIES
39
- activesupport
123
+ amazing_print
40
124
  bundler (~> 2.0)
41
125
  httplog
126
+ irbtools
42
127
  pry
43
- rake (~> 13.0)
128
+ rake
129
+ rspec
44
130
  twitter_labs_api!
131
+ webmock
45
132
 
46
133
  BUNDLED WITH
47
134
  2.1.4
data/README.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # twitter-labs-api
2
2
 
3
+ [![Labs v2](https://img.shields.io/static/v1?label=Twitter%20API&message=Developer%20Labs%20v2&color=192430&style=flat&logo=Twitter)](https://developer.twitter.com/en/docs/labs/overview/versioning)
4
+
3
5
  A basic implementation of a Twitter Labs API client as a handy Ruby [gem](https://rubygems.org/gems/twitter_labs_api). This project uses the v2 endpoints announced [here](https://twittercommunity.com/t/releasing-a-new-version-of-labs-endpoints/134219/3).
4
6
 
5
7
  ## Usage
6
8
 
7
9
  ### Prerequisite
8
- All one needs is a Twitter [bearer token](https://developer.twitter.com/en/docs/basics/authentication/oauth-2-0/bearer-tokens) to get started.
10
+ All one needs is a Twitter [bearer token](https://developer.twitter.com/en/docs/basics/authentication/oauth-2-0/bearer-tokens) to get started. The bearer token is available on the 'Tokens and Keys' page within your app's dashboard on the [Twitter for Developers](https://developer.twitter.com/) site.
9
11
 
10
- One easy way to get a bearer token is to use [this method](https://www.rubydoc.info/gems/twitter/Twitter/REST/Client#bearer_token%3F-instance_method) from https://github.com/sferik/twitter.
12
+ Alternatively, one can get a bearer token using [this method](https://www.rubydoc.info/gems/twitter/Twitter/REST/Client#bearer_token%3F-instance_method) from https://github.com/sferik/twitter.
11
13
 
12
14
  ### Setup
13
15
 
@@ -19,7 +21,7 @@ gem install twitter_labs_api
19
21
 
20
22
  #### Getting a Tweet by ID
21
23
  ```ruby
22
- requre `twitter_labs_api`
24
+ require `twitter_labs_api`
23
25
 
24
26
  api = TwitterLabsAPI.new(bearer_token: 'YOUR-BEARER-TOKEN')
25
27
 
@@ -30,19 +32,18 @@ api.get_tweet(id: '1234671272602193920')
30
32
 
31
33
  #### Specifying which fields to include in the response
32
34
 
33
- By default, the gem requests the 'default' fields for each entity. See the [API Reference](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference) for available fields. One can customize the response payload like so:
35
+ By default, the gem requests the 'default' fields for each entity. See the [API Reference](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference) for available fields. One can customize the response payload, depending on the requested resource.
34
36
 
37
+ For example, to request the URL of a Tweet's embedded media item:
35
38
  ```ruby
36
- my_fields = %w[id author_id created_at text]
37
-
38
- api.get_tweet(id: '1235508591232090112', tweet_fields: my_fields)
39
+ requested_fields = { tweet: %w[id username], media: %w[url] }
39
40
 
40
- >> {"author_id"=>"229708614", "created_at"=>"2020-03-05T10:12:57.000Z", "id"=>"1235508591232090112", "text"=>"Hot take: coronavirus will not boost remote work in the long run because spur-of-the-moment work-from-home for in-person companies is likely to be a shitshow."}
41
+ api.get_tweet(id: my_id, fields: requested_fields)
41
42
  ```
42
43
 
43
44
  #### API Errors
44
45
 
45
- Sometimes the API will respond with an error, for example `429 Too Many Requests`. The gem will throw an error with the `Net::HTTP` response as an attribute for proper exception-handling by the consuming app:
46
+ Sometimes the API will respond with an error, for example, `429 Too Many Requests`. The gem will throw an error with the `Net::HTTP` response as an attribute for proper exception-handling by the consuming app:
46
47
 
47
48
  ```ruby
48
49
  def my_twitter_request
@@ -58,14 +59,24 @@ end
58
59
  ### Status
59
60
  Currently, the following endpoints are implemented:
60
61
 
61
- - `TwitterLabsAPI#get_tweet` - Retrieve a single Tweet object with an `id`
62
- - `TwitterLabsAPI#get_tweets` - Retrieve multiple Tweets with a collection of `ids`
63
- - `TwitterLabsAPI#get_user` - Retrieve a single user object with an `id`
64
- - `TwitterLabsAPI#get_users` - Retrieve multiple user objects with a collection of `ids`
62
+ #### Tweets
63
+
64
+ - `TwitterLabsAPI#get_tweet` ([docs](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference/get-tweets-id)) - Retrieve a single Tweet object with an `id`
65
+ - `TwitterLabsAPI#get_tweets` ([docs](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference/get-tweets)) - Retrieve multiple Tweets with a collection of `ids`
66
+ - `TwitterLabsAPI#hide_reply` ([docs](https://developer.twitter.com/en/docs/labs/hide-replies/api-reference/put-hidden)) - Hide a reply by referencing it's `id`; must be in a conversation belonging to the authenticating user
67
+ - `TwitterLabsAPI#search` ([docs](https://developer.twitter.com/en/docs/labs/recent-search/api-reference/get-recent-search)) - Returns Tweets from the last 7 days that match a search query.
68
+
69
+ #### Users
70
+
71
+ - `TwitterLabsAPI#get_user` ([docs](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference/get-users-id)) - Retrieve a single user object with an `id`
72
+ - `TwitterLabsAPI#get_users` ([docs](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference/get-users)) - Retrieve multiple user objects with a collection of `ids`
73
+ - `TwitterLabsAPI#get_users_by_username` ([docs](https://developer.twitter.com/en/docs/labs/tweets-and-users/api-reference/get-users)) - Retrieve multiple user objects with a collection of `usernames`
65
74
 
66
75
  ## Roadmap
67
76
 
68
- Since this project is initially driven by my own usage of the API, I will focus on implementing and refinining the Tweets, Users, and Metrics endpoints. If this repo gets enough interest, I might implement the other endpoints and create a proper `.gemspec`. And of course, contributions are welcome :)
77
+ Currently focused on implementing support for all v2 endpoints; if there is enough interest, I will add v1 endpoint support as well.
78
+
79
+ And of course, contributions are welcome :)
69
80
 
70
81
  ## Dependencies
71
82
 
@@ -0,0 +1 @@
1
+ bundle exec rspec
@@ -2,119 +2,13 @@ require 'json'
2
2
  require 'net/http'
3
3
  require 'uri'
4
4
  require 'active_support/core_ext/hash/indifferent_access'
5
-
6
- DEFAULT_TWEET_FIELDS = %w[id author_id created_at lang public_metrics].freeze
7
- DEFAULT_USER_FIELDS = %w[name username].freeze
5
+ require_relative 'twitter_labs_api/client'
8
6
 
9
7
  # A basic implementation of a Twitter Labs API client.
10
- class TwitterLabsAPI
11
- attr_accessor :bearer_token, :debug, :api_response, :parsed_response
12
-
13
- class APIError < StandardError
14
- DEFAULT_MESSAGE = 'Twitter Labs API error, check the response attribute'.freeze
15
-
16
- attr_reader :response
17
-
18
- def initialize(msg = DEFAULT_MESSAGE, response = nil)
19
- @response = response
20
-
21
- super(msg)
8
+ module TwitterLabsAPI
9
+ class << self
10
+ def new(bearer_token:, debug: false)
11
+ Client.new(bearer_token: bearer_token, debug: debug)
22
12
  end
23
13
  end
24
-
25
- def initialize(bearer_token:, debug: false)
26
- @bearer_token = bearer_token
27
- @debug = debug
28
- require 'httplog' if debug
29
- end
30
-
31
- # @param [String] :id the ID of the requested Tweet
32
- # @param [Array<String>] :tweet_fields (["id", "author_id", "created_at", "lang", "public_metrics"]) the list of fields to retrieve for the given tweet
33
- def get_tweet(id:, tweet_fields: DEFAULT_TWEET_FIELDS)
34
- url = "https://api.twitter.com/labs/2/tweets/#{id}"
35
- params = {
36
- 'tweet.fields' => tweet_fields.join(',')
37
- }.compact
38
-
39
- make_request(url: url, params: params)
40
- end
41
-
42
- # @param [Array<String>] :ids the collection of requested Tweet IDs
43
- # @param [Array<String>] :tweet_fields (["id", "author_id", "created_at", "lang", "public_metrics"]) the list of fields to retrieve for the given tweet
44
- def get_tweets(ids:, tweet_fields: DEFAULT_TWEET_FIELDS)
45
- url = 'https://api.twitter.com/labs/2/tweets'
46
- params = {
47
- 'ids' => ids.join(','),
48
- 'tweet.fields' => tweet_fields.join(',')
49
- }.compact
50
-
51
- make_request(url: url, params: params, is_collection: true)
52
- end
53
-
54
- # @param [String] :id the ID of the requested User
55
- # @param [Array<String>] :user_fields (["name", "username"]) the list of fields to retrieve for the given User
56
- def get_user(id:, user_fields: DEFAULT_USER_FIELDS)
57
- url = "https://api.twitter.com/labs/2/users/#{id}"
58
- params = {
59
- 'user.fields' => user_fields.join(',')
60
- }.compact
61
-
62
- make_request(url: url, params: params)
63
- end
64
-
65
- # @param [Array<String>] :ids the collection of requested User IDs
66
- # @param [Array<String>] :user_fields (["name", "username"]) the list of fields to retrieve for the given User
67
- def get_users(ids:, user_fields: DEFAULT_USER_FIELDS)
68
- url = 'https://api.twitter.com/labs/2/users'
69
- params = {
70
- 'ids' => ids.join(','),
71
- 'user.fields' => user_fields.join(',')
72
- }.compact
73
-
74
- make_request(url: url, params: params, is_collection: true)
75
- end
76
-
77
- private
78
-
79
- def make_request(url:, params: {}, is_collection: false)
80
- uri = URI.parse(url)
81
- uri.query = URI.encode_www_form(params)
82
- request = Net::HTTP::Get.new(uri)
83
- request['Authorization'] = "Bearer #{bearer_token}"
84
- req_options = { use_ssl: uri.scheme == 'https' }
85
-
86
- self.api_response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
87
- http.request(request)
88
- end
89
-
90
- raise_http_error unless api_response.is_a?(Net::HTTPSuccess)
91
-
92
- self.parsed_response = JSON.parse(api_response.body)
93
-
94
- handle_api_error if error_response?
95
-
96
- is_collection ? handle_collection : handle_single
97
- end
98
-
99
- def error_response?
100
- parsed_response.key?('errors')
101
- end
102
-
103
- def handle_single
104
- parsed_response['data'].with_indifferent_access
105
- end
106
-
107
- def handle_collection
108
- parsed_response['data'].map(&:with_indifferent_access)
109
- end
110
-
111
- def raise_http_error
112
- raise(APIError.new("#{api_response.code} #{api_response.msg}", api_response))
113
- end
114
-
115
- def handle_api_error
116
- error = parsed_response['errors'].first
117
-
118
- raise APIError.new("#{error['title']}: #{error['detail']} #{error['type']}", api_response)
119
- end
120
14
  end
@@ -0,0 +1,13 @@
1
+ module TwitterLabsAPI
2
+ class APIError < StandardError
3
+ DEFAULT_MESSAGE = 'Twitter Labs API error, check the response attribute'.freeze
4
+
5
+ attr_reader :response
6
+
7
+ def initialize(msg = DEFAULT_MESSAGE, response = nil)
8
+ @response = response
9
+
10
+ super(msg)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,73 @@
1
+ require_relative 'version'
2
+ require_relative 'api_error'
3
+ require_relative 'resources/tweet'
4
+ require_relative 'resources/user'
5
+
6
+ module TwitterLabsAPI
7
+ class Client
8
+ include Resources::Tweet
9
+ include Resources::User
10
+
11
+ attr_accessor :bearer_token, :debug, :api_response, :parsed_response
12
+
13
+ def initialize(bearer_token:, debug: false)
14
+ @bearer_token = bearer_token
15
+ @debug = debug
16
+ require 'httplog' if debug
17
+ end
18
+
19
+ private
20
+
21
+ def make_request(url:, params: {}, is_collection: false, method: :get)
22
+ uri = URI.parse(url)
23
+ uri.query = URI.encode_www_form(params)
24
+ request = http_adapter(method).new(uri)
25
+ request['Authorization'] = "Bearer #{bearer_token}"
26
+ request['User-Agent'] = "twitter_labs_api gem #{TwitterLabsAPI::VERSION}"
27
+ req_options = { use_ssl: uri.scheme == 'https' }
28
+
29
+ self.api_response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
30
+ http.request(request)
31
+ end
32
+
33
+ raise_http_error unless api_response.is_a?(Net::HTTPSuccess)
34
+
35
+ self.parsed_response = JSON.parse(api_response.body)
36
+
37
+ handle_api_error if error_response?
38
+
39
+ is_collection ? handle_collection : handle_single
40
+ end
41
+
42
+ def http_adapter(method)
43
+ case method
44
+ when :put
45
+ Net::HTTP::Put
46
+ else
47
+ Net::HTTP::Get
48
+ end
49
+ end
50
+
51
+ def error_response?
52
+ parsed_response.key?('errors')
53
+ end
54
+
55
+ def handle_single
56
+ parsed_response['data'].with_indifferent_access
57
+ end
58
+
59
+ def handle_collection
60
+ parsed_response['data'].map(&:with_indifferent_access)
61
+ end
62
+
63
+ def raise_http_error
64
+ raise(APIError.new("#{api_response.code} #{api_response.msg}", api_response))
65
+ end
66
+
67
+ def handle_api_error
68
+ error = parsed_response['errors'].first
69
+
70
+ raise APIError.new("#{error['title']}: #{error['detail']} #{error['type']}", api_response)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,58 @@
1
+ module TwitterLabsAPI
2
+ module Resources
3
+ module Tweet
4
+ DEFAULT_TWEET_FIELDS = %w[id author_id created_at lang public_metrics].freeze
5
+ DEFAULT_FIELDS = { tweet: DEFAULT_TWEET_FIELDS }.freeze
6
+
7
+ # Returns a variety of information about a single Tweet specified by the requested ID.
8
+ # @param [String] :id the ID of the requested Tweet
9
+ # @param [Hash] :fields a hash for fields to include in the response payload;
10
+ #
11
+ # e.g.: { tweet: %w[id username], media: %w[url] }
12
+ # @return Hash an object with requested tweet fields
13
+ def get_tweet(id:, fields: DEFAULT_FIELDS)
14
+ url = "https://api.twitter.com/labs/2/tweets/#{id}"
15
+ params = ParamsService.from_fields(fields)
16
+
17
+ make_request(url: url, params: params)
18
+ end
19
+
20
+ # Returns a variety of information about the Tweet specified by the requested ID or list of IDs.
21
+ # @param [Array<String>] :ids the collection of requested Tweet IDs
22
+ # @param [Hash] :fields a hash for fields to include in the response payload;
23
+ #
24
+ # e.g.: { tweet: %w[id username], media: %w[url] }
25
+ # @return [Array<Hash>] of tweet objects with the requested tweet fields
26
+ def get_tweets(ids:, fields: DEFAULT_FIELDS)
27
+ url = 'https://api.twitter.com/labs/2/tweets'
28
+ params = ParamsService.from_fields(fields)
29
+ params.merge!({ ids: ids.join(',') })
30
+
31
+ make_request(url: url, params: params, is_collection: true)
32
+ end
33
+
34
+ # Hides or unhides a reply to a Tweet.
35
+ # @param [String] :id the ID of the requested Tweet; must belong to a conversation by the authenticated user
36
+ # @return boolean indicating the hidden status of the requested tweet
37
+ def hide_reply(id:)
38
+ url = "https://api.twitter.com/labs/2/tweets/#{id}/hidden"
39
+
40
+ make_request(url: url, method: :put)[:hidden]
41
+ end
42
+
43
+ # The Labs recent search endpoint returns Tweets from the last 7 days that match a search query.
44
+ # @param [String] :query the search query
45
+ # @param [Hash] :fields a hash for fields to include in the response payload;
46
+ #
47
+ # e.g.: { tweet: %w[id username], media: %w[url] }
48
+ # @return [Array<Hash>] of tweet objects with the requested tweet fields
49
+ def search(query:, fields: DEFAULT_FIELDS)
50
+ url = 'https://api.twitter.com/labs/2/tweets/search'
51
+ params = ParamsService.from_fields(fields)
52
+ params.merge!({ query: query })
53
+
54
+ make_request(url: url, params: params, is_collection: true)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ module TwitterLabsAPI
2
+ module Resources
3
+ module User
4
+ DEFAULT_USER_FIELDS = %w[id name username].freeze
5
+ DEFAULT_FIELDS = { user: DEFAULT_USER_FIELDS }.freeze
6
+
7
+ # Returns a variety of information about a single more user specified by the requested ID.
8
+ # @param [String] :id the ID of the requested User
9
+ # @param [Hash] :fields a hash for fields to include in the response payload;
10
+ #
11
+ # e.g.: { user: %w[id name username] }
12
+ # @return Hash an object with requested user fields
13
+ def get_user(id:, fields: DEFAULT_FIELDS)
14
+ url = "https://api.twitter.com/labs/2/users/#{id}"
15
+ params = ParamsService.from_fields(fields)
16
+
17
+ make_request(url: url, params: params)
18
+ end
19
+
20
+ # Returns a variety of information about one or more Users specified by the requested IDs.
21
+ # @param [Array<String>] :ids the collection of requested User IDs
22
+ # @param [Hash] :fields a hash for fields to include in the response payload;
23
+ #
24
+ # e.g.: { user: %w[id name username] }
25
+ # @return [Array<Hash>] of user objects with the requested user fields
26
+ def get_users(ids:, fields: DEFAULT_FIELDS)
27
+ url = 'https://api.twitter.com/labs/2/users'
28
+ params = ParamsService.from_fields(fields)
29
+ params.merge!({ ids: ids.join(',') })
30
+
31
+ make_request(url: url, params: params, is_collection: true)
32
+ end
33
+
34
+ # Returns a variety of information about one or more Users specified by the requested usernames.
35
+ # @param [Array<String>] :usernames the collection of requested Usernames
36
+ # @param [Hash] :fields a hash for fields to include in the response payload;
37
+ #
38
+ # e.g.: { user: %w[id name username] }
39
+ # @return [Array<Hash>] of user objects with the requested user fields
40
+ def get_users_by_usernames(usernames:, fields: DEFAULT_FIELDS)
41
+ url = 'https://api.twitter.com/labs/2/users/by'
42
+ params = ParamsService.from_fields(fields)
43
+ params.merge!({ usernames: usernames.join(',') })
44
+
45
+ make_request(url: url, params: params, is_collection: true)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ class ParamsService
2
+ # Convert user-passed fields hash to query params
3
+ # @param [Hash] :fields A hash of requested fields; see API Reference for details
4
+ # @return [Hash] A hash of query params for consumption by API client
5
+ # @example
6
+ # input: { tweet: %w[id username], media: ['url'] }
7
+ # output: { 'tweet.fields' => 'id,username', 'media.fields' => 'url }
8
+ def self.from_fields(fields)
9
+ fields.keys.inject({}) do |memo, key|
10
+ memo["#{key}.fields"] = fields[key].join(',')
11
+
12
+ memo
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
- class TwitterLabsAPI
2
- VERSION = '0.4.0'.freeze
1
+ module TwitterLabsAPI
2
+ VERSION = '0.7.0'.freeze
3
3
  end
@@ -25,6 +25,9 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ['lib']
27
27
 
28
+ spec.add_dependency 'activesupport', '~> 6.0'
29
+ spec.add_dependency 'httplog', '~> 1.4'
30
+
28
31
  spec.add_development_dependency 'bundler', '~> 2.0'
29
32
  spec.add_development_dependency 'rake', '~> 13.0'
30
33
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitter_labs_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tomholford
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-24 00:00:00.000000000 Z
11
+ date: 2020-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httplog
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -45,7 +73,9 @@ executables: []
45
73
  extensions: []
46
74
  extra_rdoc_files: []
47
75
  files:
76
+ - ".github/workflows/ruby.yml"
48
77
  - ".gitignore"
78
+ - ".rspec"
49
79
  - CHANGELOG.md
50
80
  - Gemfile
51
81
  - Gemfile.lock
@@ -54,7 +84,13 @@ files:
54
84
  - Rakefile
55
85
  - bin/console
56
86
  - bin/setup
87
+ - bin/specs
57
88
  - lib/twitter_labs_api.rb
89
+ - lib/twitter_labs_api/api_error.rb
90
+ - lib/twitter_labs_api/client.rb
91
+ - lib/twitter_labs_api/resources/tweet.rb
92
+ - lib/twitter_labs_api/resources/user.rb
93
+ - lib/twitter_labs_api/services/params_service.rb
58
94
  - lib/twitter_labs_api/version.rb
59
95
  - twitter-labs-api.gemspec
60
96
  homepage: https://github.com/tomholford/twitter-labs-api