mirror-api 0.0.9 → 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/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-pro
data/.rspec CHANGED
@@ -1 +1 @@
1
- --colour
1
+ --colour --format d
data/README.md CHANGED
@@ -4,7 +4,12 @@
4
4
 
5
5
  # Mirror::Api
6
6
 
7
- Simple Mirror Api client library
7
+ Simple Mirror Api client library.
8
+
9
+ ## Benefits
10
+
11
+ - Robust error handling. You can choose whether to bubble errors or not.
12
+ - Snake case(ruby friendly) notation for requests and responses
8
13
 
9
14
  ## Installation
10
15
 
@@ -22,31 +27,143 @@ Or install it yourself as:
22
27
 
23
28
  ## Usage
24
29
 
25
- ``` ruby
26
-
30
+ ##Getting Started
31
+ ###Require the mirror-api gem.
32
+ ```ruby
27
33
  require "mirror-api"
34
+ ```
35
+ ### Authenticating your client
36
+ ```ruby
37
+ token = Mirror::OAuth.new(client_id, client_secret, refresh_token)
28
38
 
29
39
  api = Mirror::Api::Client.new(token)
40
+ ```
41
+ ##[Timeline](https://developers.google.com/glass/v1/reference/timeline)
30
42
 
31
- # Getting all the timeline items
43
+ ### [Listing Timeline items](https://developers.google.com/glass/v1/reference/timeline/list)
44
+ ```ruby
32
45
  items = api.timeline.list
46
+ ```
47
+
48
+ ### [Inserting a Timeline item](https://developers.google.com/glass/v1/reference/timeline/insert)
49
+ ```ruby
50
+ item_1 = api.timeline.insert({text: "What up WORLD?!?!"})
51
+ ```
52
+
53
+ ### [Inserting a Timeline item with reply actions](https://developers.google.com/glass/timeline#user_interaction_with_menu_items)
54
+ ```ruby
55
+ item_2 = api.timeline.insert({text: "Do you like tacos?", menu_items:[{action: "REPLY"}]})
56
+ ```
57
+
58
+ ### [Updating a Timeline item](https://developers.google.com/glass/v1/reference/timeline/update)
59
+ ```ruby
60
+ txt = "Seriously, do you like tacos? This is the second time I had to ask you."
61
+ item_2 = api.timeline.update(item_2.id, {text: txt, menu_items:[{action: "REPLY"}]})
62
+ ```
63
+
64
+ ### [Patching a Timeline item](https://developers.google.com/glass/v1/reference/timeline/patch)
65
+ ```ruby
66
+ item_2 = api.timeline.patch(item_2.id, {text: "You realize you are a bad friend right?", menu_items:[{action: "REPLY"}]})
67
+ ```
68
+
69
+ ### [Getting a Timeline item](https://developers.google.com/glass/v1/reference/timeline/get)
70
+ ```ruby
71
+ api.timeline.get(item_2.id)
72
+ ```
73
+
74
+ ### [Deleting a Timeline item](https://developers.google.com/glass/v1/reference/timeline/delete)
75
+ ```ruby
76
+ api.timeline.delete(item_2.id)
77
+ ```
78
+
79
+ ##[Timeline Attachments](https://developers.google.com/glass/v1/reference/timeline/attachments)
80
+
81
+ ### [Listing Timeline Attachments](https://developers.google.com/glass/v1/reference/timeline/attachments/list)
82
+ ```ruby
83
+ attachments = api.timeline.list(item_1.id, {attachments:{}})
84
+ ```
85
+
86
+ ### [Getting a Timeline Attachment](https://developers.google.com/glass/v1/reference/timeline/attachments/get)
87
+ ```ruby
88
+ #for the sake of getting an id...
89
+ attachment = attachments.items.first
90
+ api.timeline.get(item_2.id, {attachments:{id: attachment.id}})
91
+ ```
33
92
 
34
- # Insert a simple text item - https://developers.google.com/glass/timeline#inserting_a_simple_timeline_item
35
- item1 = api.timeline.create({text: "Hello Word"})
93
+ ### [Deleting a Timeline Attachment](https://developers.google.com/glass/v1/reference/timeline/attachments/delete)
94
+ ```ruby
95
+ api.timeline.delete(item_2.id, {attachments:{id: attachment.id}})
96
+ ```
97
+
98
+ ##[Subscriptions](https://developers.google.com/glass/v1/reference/subscriptions)
99
+
100
+ ### [Listing Subscriptions](https://developers.google.com/glass/v1/reference/subscriptions/list)
101
+ ```ruby
102
+ subscriptions = api.subscriptions.list
103
+ ```
104
+
105
+ ### [Inserting a Subscription](https://developers.google.com/glass/v1/reference/subscriptions/insert)
106
+ ```ruby
107
+ subscription = api.subscriptions.insert({collection: "timeline", userToken:"user_1", operation: ["UPDATE"], callbackUrl: "https://yourawesomewebsite.com/callback"})
108
+ ```
36
109
 
37
- # Inserting an item with reply actions - https://developers.google.com/glass/timeline#user_interaction_with_menu_items
38
- item2 = api.timeline.create({text: "Hello Word", menu_items:[{action: "REPLY"}]})
110
+ ### [Updating a Subscription](https://developers.google.com/glass/v1/reference/subscriptions/update)
111
+ ```ruby
112
+ item_2 = api.subscriptions.update(subscription.id, {collection: "timeline", operation: ["UPDATE", "INSERT", "DELETE"], callbackUrl: "https://yourawesomewebsite.com/callback"})
39
113
 
40
- item2 = api.timeline.update(item2.id, {text: "Hello Again Word", menu_items:[{action: "REPLY"}]})
114
+ ```
115
+
116
+ ### [Deleting a Subscription](https://developers.google.com/glass/v1/reference/subscriptions/delete)
117
+ ```ruby
118
+ api.subscriptions.delete(item_2.id)
119
+ ```
120
+
121
+ ##[Locations](https://developers.google.com/glass/v1/reference/locations)
122
+
123
+ ### [Listing Locations](https://developers.google.com/glass/v1/reference/locations/list)
124
+ ```ruby
125
+ locations = api.locations.list
126
+ ```
41
127
 
42
- api.timeline.delete(item2.id)
128
+ ### [Getting a Location](https://developers.google.com/glass/v1/reference/locations/get)
129
+ ```ruby
130
+ #for the sake of getting an id...
131
+ location = locations.items.first
132
+ api.locations.get(location.id)
43
133
  ```
44
134
 
45
- ## See Also
135
+ ##[Contacts](https://developers.google.com/glass/v1/reference/contacts)
46
136
 
47
- Generic Google API Ruby Client
137
+ ### [Listing Contacts](https://developers.google.com/glass/v1/reference/contacts/list)
138
+ ```ruby
139
+ items = api.contacts.list
140
+ ```
141
+
142
+ ### [Inserting a Contact](https://developers.google.com/glass/v1/reference/contacts/insert)
143
+ ```ruby
144
+ contact = api.contacts.insert({id: '1234', displayName: 'Troll', imageUrls: ["http://pixelr3ap3r.com/wp-content/uploads/2012/08/357c6328ee4b11e1bfbf22000a1c91a7_7.jpg"]})
145
+ ```
146
+
147
+ ### [Updating a Contact](https://developers.google.com/glass/v1/reference/contacts/update)
148
+ ```ruby
149
+ contact = api.contacts.update(contact.id, {displayName: 'Unicorn'})
150
+ ```
151
+
152
+ ### [Patching a Contact](https://developers.google.com/glass/v1/reference/contacts/patch)
153
+ ```ruby
154
+ contact = api.contacts.patch(contact.id, {displayName: 'Grumpy Cat', imageUrls: ["http://blog.catmoji.com/wp-content/uploads/2012/09/grumpy-cat.jpeg"]})
155
+ ```
156
+
157
+ ### [Getting a Contact](https://developers.google.com/glass/v1/reference/contacts/get)
158
+ ```ruby
159
+ api.contacts.get(contact.id)
160
+ ```
161
+
162
+ ### [Deleting a Contact](https://developers.google.com/glass/v1/reference/contacts/delete)
163
+ ```ruby
164
+ api.contacts.delete(contact.id)
165
+ ```
48
166
 
49
- https://github.com/google/google-api-ruby-client
50
167
 
51
168
  ## Contributing
52
169
 
data/lib/mirror-api.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  require "mirror-api/version"
2
- require "mirror-api/base"
3
2
  require "mirror-api/client"
4
3
  require "mirror-api/oauth"
@@ -4,30 +4,36 @@ module Mirror
4
4
  module Api
5
5
  class Client
6
6
 
7
- def initialize(credentials)
8
- @credentials = if credentials.is_a?(String)
9
- {:token => credentials}
10
- elsif credentials.is_a?(Hash)
11
- credentials
12
- end
13
-
14
- raise "Invalid credentials #{credentials.inspect}" unless @credentials
7
+ attr_accessor :credentials, :options
8
+
9
+ def initialize(credentials, options={raise_errors: false})
10
+ self.credentials = credentials
11
+ self.options = options
12
+ raise "Invalid credentials. Missing token" unless (self.credentials && self.credentials[:token])
13
+ end
14
+
15
+ def credentials=(value)
16
+ if value.is_a?(String)
17
+ @credentials = {:token => value}
18
+ elsif value.is_a?(Hash)
19
+ @credentials = value
20
+ end
15
21
  end
16
22
 
17
23
  def timeline
18
- @timeline ||= Resource.new(@credentials)
24
+ @timeline ||= Resource.new(credentials, Request::TIMELINE, options)
19
25
  end
20
26
 
21
27
  def subscriptions
22
- @subscriptions ||= Resource.new(@credentials, Request::SUBSCRIPTIONS)
28
+ @subscriptions ||= Resource.new(credentials, Request::SUBSCRIPTIONS, options)
23
29
  end
24
30
 
25
31
  def locations
26
- @locations ||= Resource.new(@credentials, Request::LOCATIONS)
32
+ @locations ||= Resource.new(credentials, Request::LOCATIONS, options)
27
33
  end
28
34
 
29
35
  def contacts
30
- @contacts ||= Resource.new(@credentials, Request::CONTACTS)
36
+ @contacts ||= Resource.new(credentials, Request::CONTACTS, options)
31
37
  end
32
38
  end
33
39
  end
@@ -0,0 +1,10 @@
1
+ module Mirror
2
+ module Api
3
+ class Errors
4
+ ERROR_400 = {code: 1, :message => "Mirror API returned a status code 400 for this call"}
5
+ ERROR_404 = {code: 2, :message => "Mirror API returned a status code 404 for this call"}
6
+ INTERNAL_ERROR = {:code => 100, :message => "We are experiencing problems requesting your name. Our team has been notified."}
7
+ TOKEN_REFRESH_ERROR = {:code => 200, :message => "Could not refresh your API access token"}
8
+ end
9
+ end
10
+ end
@@ -12,12 +12,14 @@ module Mirror
12
12
  req = Net::HTTP::Post.new("/o/oauth2/token")
13
13
  req.set_form_data(client_id: self.client_id, client_secret: self.client_secret, refresh_token: self.refresh_token, grant_type: "refresh_token")
14
14
  res = Net::HTTP.start("accounts.google.com", use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |http| http.request(req) }
15
-
16
- begin
17
- result = JSON.parse(res.body)
18
- result["access_token"]
19
- rescue
20
- raise JSON.parse(res.body)['error']['message']
15
+ result = JSON.parse(res.body)
16
+
17
+ if result
18
+ if result["access_token"]
19
+ result["access_token"]
20
+ elsif result["error"]
21
+ raise "Error in get_access_token #{result["error"]}"
22
+ end
21
23
  end
22
24
  end
23
25
 
@@ -1,22 +1,163 @@
1
- require_relative "base"
1
+ require "rest-client"
2
+ require "json"
3
+ require "logger"
4
+ require_relative "request_data"
5
+ require_relative "response_data"
6
+ require_relative "errors"
2
7
 
3
8
  module Mirror
4
9
  module Api
5
10
  HOST = "https://www.googleapis.com"
6
11
 
7
- class Request < Mirror::Api::Base
12
+ class Request
8
13
  TIMELINE = "timeline"
9
14
  SUBSCRIPTIONS = "subscriptions"
10
15
  LOCATIONS = "locations"
11
16
  CONTACTS = "contacts"
12
17
 
18
+ VALID_RESOURCES = [TIMELINE, SUBSCRIPTIONS, LOCATIONS, CONTACTS]
19
+
20
+ attr_accessor :last_error, :logger, :host, :last_exception, :throw_on_fail, :response, :data, :creds, :resource, :params
21
+
22
+
13
23
  def initialize(creds, options={})
14
- @resource = options[:resource] || TIMELINE
24
+ self.resource = options[:resource]
25
+ self.params = options[:params]
26
+ self.logger = options[:logger]
15
27
  @id = options[:id]
16
- @params = options[:params]
28
+
17
29
  @expected_response = options[:expected_response]
18
- host = options[:host] || HOST
19
- super(creds, options[:raise_errors], host, options[:logger])
30
+ @creds = creds
31
+ @last_exception = nil
32
+ @throw_on_fail = options[:raise_errors] || false
33
+ @host = options[:host] || HOST
34
+
35
+ @last_error = nil
36
+ end
37
+
38
+ def logger=(value)
39
+ if value
40
+ if value.is_a?(Logger)
41
+ @logger = value
42
+ else
43
+ raise "Invalid object given as logger #{value.inspect}"
44
+ end
45
+ end
46
+ end
47
+
48
+ def resource=(value)
49
+ if value
50
+ if VALID_RESOURCES.include?(value)
51
+ @resource = value
52
+ else
53
+ raise "Invalid resource name #{value}"
54
+ end
55
+ end
56
+ @resource = TIMELINE unless @resource
57
+ end
58
+
59
+ def params=(value)
60
+ if value
61
+ if value.is_a?(RequestData)
62
+ @params = value
63
+ elsif value.is_a?(Hash) && value.keys.count > 0
64
+ @params = RequestData.new(value)
65
+ else
66
+ raise "Parameter #{value.inspect} is not compatible"
67
+ end
68
+ else
69
+ @params = nil
70
+ end
71
+ end
72
+
73
+ public
74
+ def post
75
+ do_verb(:post)
76
+ end
77
+
78
+ def put
79
+ do_verb(:put)
80
+ end
81
+
82
+ def patch
83
+ do_verb(:patch)
84
+ end
85
+
86
+ def delete
87
+ get_verb(:delete)
88
+ end
89
+
90
+ def get
91
+ get_verb
92
+ end
93
+
94
+ protected
95
+
96
+ def handle_http_response(response, request, result, &block)
97
+ @request = request
98
+ case response.code
99
+ when 404
100
+ when 400
101
+ if @logger
102
+ msg = "ERROR - #{response.code} #{request.inspect} to #{self.invoke_url} with params #{self.params}. Response is #{response.body}"
103
+ @logger.error(msg)
104
+ end
105
+ response
106
+ else
107
+ response.return!(request, result, &block)
108
+ end
109
+ end
110
+
111
+ def successful_response?
112
+ @response and @response.code == expected_response
113
+ end
114
+
115
+ def headers
116
+ {
117
+ "Accept" => "application/json",
118
+ "Content-type" => "application/json",
119
+ "Authorization" => "Bearer #{@creds[:token]}"
120
+ }
121
+ end
122
+
123
+ def handle_response
124
+ if successful_response?
125
+ ret_val
126
+ else
127
+ send_error
128
+ end
129
+ end
130
+
131
+ def handle_error(error_desc, msg, errors, validation_error=nil, params={})
132
+ @last_error = error_desc.dup
133
+ @last_error[:errors] = errors
134
+ @last_error[:validation_error] = validation_error if validation_error
135
+ msg += " with params #{params}"
136
+ @logger.warn(msg) if @logger
137
+ raise error_desc[:message] if throw_on_fail
138
+ end
139
+
140
+ def set_data
141
+ if @response and @response.body
142
+ @data = JSON.parse(@response.body) if @response.body.is_a?(String) && !@response.body.empty?
143
+ end
144
+ end
145
+
146
+ def do_verb(verb=:post)
147
+ data = self.params.to_json
148
+ @response = RestClient.send(verb, self.invoke_url, data, self.headers) do |response, request, result, &block|
149
+ handle_http_response(response, request, result, &block)
150
+ end
151
+ set_data
152
+ handle_response
153
+ end
154
+
155
+ def get_verb(verb=:get)
156
+ @response = RestClient.send(verb, self.invoke_url, self.headers) do |response, request, result, &block|
157
+ handle_http_response(response, request, result, &block)
158
+ end
159
+ set_data
160
+ handle_response
20
161
  end
21
162
 
22
163
  def invoke_url
@@ -31,20 +172,24 @@ module Mirror
31
172
  end
32
173
 
33
174
  def attachments
34
- params[:attachments] if params
35
- end
36
-
37
- def params
38
- @params ||={}
175
+ params.attachments if params
39
176
  end
40
177
 
41
178
  def ret_val
42
- Hashie::Mash.new(@data)
179
+ ResponseData.new(@data)
43
180
  end
44
181
 
45
182
  def expected_response
46
183
  @expected_response
47
184
  end
185
+
186
+ def send_error
187
+ return handle_error(
188
+ Mirror::Api::Errors::ERROR_400,
189
+ "Error making a request for #{@resource}",
190
+ @data
191
+ )
192
+ end
48
193
  end
49
194
  end
50
195
  end