mirror-api 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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