vhx-ruby 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/README.md +59 -0
- data/Rakefile +1 -0
- data/lib/vhx.rb +66 -0
- data/lib/vhx/client.rb +86 -0
- data/lib/vhx/error.rb +24 -0
- data/lib/vhx/middleware/error_response.rb +32 -0
- data/lib/vhx/middleware/oauth2.rb +22 -0
- data/lib/vhx/oauth_token.rb +11 -0
- data/lib/vhx/objects/authorization.rb +5 -0
- data/lib/vhx/objects/collection.rb +8 -0
- data/lib/vhx/objects/collection_item.rb +4 -0
- data/lib/vhx/objects/customer.rb +8 -0
- data/lib/vhx/objects/product.rb +6 -0
- data/lib/vhx/objects/site.rb +4 -0
- data/lib/vhx/objects/user.rb +10 -0
- data/lib/vhx/objects/video.rb +7 -0
- data/lib/vhx/objects/video_file.rb +4 -0
- data/lib/vhx/utilities/api_operations/create.rb +22 -0
- data/lib/vhx/utilities/api_operations/delete.rb +16 -0
- data/lib/vhx/utilities/api_operations/list.rb +21 -0
- data/lib/vhx/utilities/api_operations/request.rb +17 -0
- data/lib/vhx/utilities/api_operations/update.rb +15 -0
- data/lib/vhx/utilities/vhx_helper.rb +20 -0
- data/lib/vhx/utilities/vhx_list_object.rb +44 -0
- data/lib/vhx/utilities/vhx_object.rb +106 -0
- data/lib/vhx/version.rb +3 -0
- data/spec/client_spec.rb +69 -0
- data/spec/fixtures/sample_array_list.json +15 -0
- data/spec/fixtures/sample_file_response.json +18 -0
- data/spec/fixtures/sample_hash_list.json +23 -0
- data/spec/fixtures/sample_package_response.json +185 -0
- data/spec/fixtures/sample_site_response.json +26 -0
- data/spec/fixtures/sample_user_response.json +21 -0
- data/spec/fixtures/sample_video_response.json +51 -0
- data/spec/middleware/error_response_spec.rb +11 -0
- data/spec/middleware/oauth2_spec.rb +14 -0
- data/spec/objects/file_spec.rb +29 -0
- data/spec/objects/package_spec.rb +74 -0
- data/spec/objects/site_spec.rb +44 -0
- data/spec/objects/user_spec.rb +51 -0
- data/spec/objects/video_spec.rb +36 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/test_data.rb +55 -0
- data/spec/utilities/vhx_collection_spec.rb +27 -0
- data/spec/utilities/vhx_helper_spec.rb +47 -0
- data/spec/utilities/vhx_object_spec.rb +53 -0
- data/spec/vcr/Vhx_Client/application_user/_refresh_access_token/access_token_changed.yml +57 -0
- data/spec/vcr/Vhx_Client/application_user/_refresh_access_token/oauth_token_refreshed.yml +57 -0
- data/spec/vcr/Vhx_File/associations/are_present.yml +409 -0
- data/spec/vcr/Vhx_Middleware_ErrorResponse/unauthorized_user_credentials.yml +122 -0
- data/spec/vcr/Vhx_Middleware_OAuth2/access_token_refresh.yml +797 -0
- data/spec/vcr/Vhx_Package/_add_video/with_hypermedia/returns_package_object.yml +51 -0
- data/spec/vcr/Vhx_Package/_add_video/with_id/returns_package_object.yml +51 -0
- data/spec/vcr/Vhx_Package/_create/returns_package_object.yml +140 -0
- data/spec/vcr/Vhx_Package/_find/with_hypermedia.yml +243 -0
- data/spec/vcr/Vhx_Package/_find/with_id.yml +243 -0
- data/spec/vcr/Vhx_Package/_remove_video/with_hypermedia/returns_success.yml +51 -0
- data/spec/vcr/Vhx_Package/_remove_video/with_id/returns_success.yml +51 -0
- data/spec/vcr/Vhx_Package/associations/are_present.yml +195 -0
- data/spec/vcr/Vhx_Site/_create/returns_site_object.yml +91 -0
- data/spec/vcr/Vhx_Site/_find/with_hypermedia.yml +195 -0
- data/spec/vcr/Vhx_Site/_find/with_id.yml +195 -0
- data/spec/vcr/Vhx_User/_find/with_hypermedia.yml +81 -0
- data/spec/vcr/Vhx_User/_find/with_id.yml +81 -0
- data/spec/vcr/Vhx_User/_me/returns_user_object.yml +720 -0
- data/spec/vcr/Vhx_User/_update/returns_user_object.yml +212 -0
- data/spec/vcr/Vhx_VhxObject/associations/cache/retreive_if_available.yml +195 -0
- data/spec/vcr/Vhx_VhxObject/associations/falls_back_to_links.yml +310 -0
- data/spec/vcr/Vhx_Video/_create/returns_video_object.yml +125 -0
- data/spec/vcr/Vhx_Video/associations/are_present.yml +294 -0
- data/vhx.gemspec +27 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: beb4e508443c33c4e403dc3af8968963b782b16d
|
4
|
+
data.tar.gz: 252a387534bc8e8eb38c6e9189cac2a6e9e501a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6e06429c037251651ce2b8ccb192f5e04f46dd0e6311e9c77282841799ad0997de16482be0db7f390b8eee227df018d4de512f149f3616f63357b6b7cc54a5d2
|
7
|
+
data.tar.gz: bbe96986befef7b8b2679d51e8c4f4a6d51207402a29a5fd237c6b93ad4ffb66ff64b6f0753e273802c1a8234cfa0781328991a07419c9268f87ae41bd865c49
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# VHX Ruby API Client
|
2
|
+
|
3
|
+
The VHX API is currently Private Beta. You can request an API key by emailing api@vhx.tv.
|
4
|
+
|
5
|
+
### Installation
|
6
|
+
|
7
|
+
`gem install vhx-ruby`
|
8
|
+
|
9
|
+
### Documentation
|
10
|
+
|
11
|
+
Documentation is available at http://dev.vhx.tv/docs/api/ruby.
|
12
|
+
Full API reference is available at http://dev.vhx.tv/docs/api?ruby.
|
13
|
+
|
14
|
+
## Getting Started
|
15
|
+
|
16
|
+
Before requesting your first resource, you must setup an instance of the Vhx Client:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
vhx = Vhx.setup({ api_key: 'your VHX API key'} )
|
20
|
+
```
|
21
|
+
|
22
|
+
Here's an example of creating a Vhx resource with payload options. You can handle errors by rescuing Vhx::VhxError.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
begin
|
26
|
+
# Example Customer Create
|
27
|
+
customer = Vhx::Customer.create({
|
28
|
+
email: 'customer@email.com',
|
29
|
+
name: 'First Last',
|
30
|
+
subscription: 'https://api.vhx.tv/subscriptions/1'
|
31
|
+
})
|
32
|
+
rescue Vhx::VhxError
|
33
|
+
# Handle error
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
### Resources & methods
|
38
|
+
|
39
|
+
customers
|
40
|
+
* [`create`](http://dev.vhx.tv/docs/api?ruby#create_customer)
|
41
|
+
* [`update`](http://dev.vhx.tv/docs/api?ruby#update_customer)
|
42
|
+
* [`retrieve`](http://dev.vhx.tv/docs/api?ruby#retrieve_customer)
|
43
|
+
* [`list`](http://dev.vhx.tv/docs/api?ruby#list_customers)
|
44
|
+
|
45
|
+
authorizations
|
46
|
+
* [`create`](http://dev.vhx.tv/docs/api?ruby#create_authorization)
|
47
|
+
|
48
|
+
videos
|
49
|
+
* [`create`](http://dev.vhx.tv/docs/api?ruby#create_customer)
|
50
|
+
* [`update`](http://dev.vhx.tv/docs/api?ruby#update_customer)
|
51
|
+
* [`retrieve`](http://dev.vhx.tv/docs/api?ruby#retrieve_customer)
|
52
|
+
* [`list`](http://dev.vhx.tv/docs/api?ruby#list_customers)
|
53
|
+
|
54
|
+
collections
|
55
|
+
* [`create`](http://dev.vhx.tv/docs/api?ruby#create_collection)
|
56
|
+
* [`update`](http://dev.vhx.tv/docs/api?ruby#update_collection)
|
57
|
+
* [`retrieve`](http://dev.vhx.tv/docs/api?ruby#retrieve_collection)
|
58
|
+
* [`list`](http://dev.vhx.tv/docs/api?ruby#list_collections)
|
59
|
+
* [`items`](http://dev.vhx.tv/docs/api?ruby#list_collection_items)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/vhx.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
require "vhx/version"
|
5
|
+
require "vhx/error"
|
6
|
+
require "vhx/oauth_token"
|
7
|
+
|
8
|
+
require 'vhx/middleware/error_response'
|
9
|
+
require 'vhx/middleware/oauth2'
|
10
|
+
|
11
|
+
require "vhx/client"
|
12
|
+
|
13
|
+
require "vhx/utilities/vhx_helper"
|
14
|
+
require "vhx/utilities/api_operations/create"
|
15
|
+
require "vhx/utilities/api_operations/delete"
|
16
|
+
require "vhx/utilities/api_operations/list"
|
17
|
+
require "vhx/utilities/api_operations/request"
|
18
|
+
require "vhx/utilities/api_operations/update"
|
19
|
+
|
20
|
+
require "vhx/utilities/vhx_object"
|
21
|
+
require "vhx/utilities/vhx_list_object"
|
22
|
+
|
23
|
+
require "vhx/objects/user"
|
24
|
+
require "vhx/objects/collection"
|
25
|
+
require "vhx/objects/collection_item"
|
26
|
+
require "vhx/objects/product"
|
27
|
+
require "vhx/objects/site"
|
28
|
+
require "vhx/objects/video"
|
29
|
+
require "vhx/objects/video_file"
|
30
|
+
require "vhx/objects/customer"
|
31
|
+
require "vhx/objects/authorization"
|
32
|
+
|
33
|
+
module Vhx
|
34
|
+
API_BASE_URL = 'https://api.vhx.tv'
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def setup(options = {})
|
38
|
+
options[:client_id] ||= @client_id
|
39
|
+
options[:client_secret] ||= @client_secret
|
40
|
+
options[:api_key] ||= @api_key
|
41
|
+
options[:api_base] ||= @api_base_url
|
42
|
+
options[:skip_auto_refresh] = @skip_auto_refresh if options[:skip_auto_refresh].nil?
|
43
|
+
Vhx.client = Vhx::Client.new(options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def config(config = {})
|
47
|
+
@client_id = config[:client_id]
|
48
|
+
@client_secret = config[:client_secret]
|
49
|
+
@api_key = config[:api_key]
|
50
|
+
@skip_auto_refresh = config[:skip_auto_refresh] || false
|
51
|
+
@api_base_url = config[:api_base]
|
52
|
+
end
|
53
|
+
|
54
|
+
def client
|
55
|
+
@client
|
56
|
+
end
|
57
|
+
|
58
|
+
def client=(new_client)
|
59
|
+
@client = new_client
|
60
|
+
end
|
61
|
+
|
62
|
+
def connection
|
63
|
+
client ? client.connection : nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/vhx/client.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Vhx
|
2
|
+
class Client
|
3
|
+
attr_reader :client_id, :client_secret, :api_base_url, :oauth_token, :api_key, :connection, :ssl
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
options = Hash[options.map{ |k, v| [k.to_sym, v] }]
|
7
|
+
@api_base_url = options[:api_base] || API_BASE_URL
|
8
|
+
@client_id = options[:client_id]
|
9
|
+
@client_secret = options[:client_secret]
|
10
|
+
@oauth_token = options[:api_key] ? nil : OAuthToken.new(options, refreshed = false)
|
11
|
+
@api_key = options[:api_key]
|
12
|
+
@skip_auto_refresh = options[:skip_auto_refresh]
|
13
|
+
@ssl = options[:ssl] || {}
|
14
|
+
@headers = {}
|
15
|
+
|
16
|
+
configure_connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure_connection
|
20
|
+
@connection = Faraday::Connection.new(url: api_base_url, headers: configured_headers, ssl: ssl) do |faraday|
|
21
|
+
faraday.request :url_encoded
|
22
|
+
faraday.request :json
|
23
|
+
faraday.response :logger
|
24
|
+
faraday.use Vhx::Middleware::OAuth2, :vhx_client => self unless @skip_auto_refresh
|
25
|
+
|
26
|
+
faraday.adapter Faraday.default_adapter
|
27
|
+
|
28
|
+
faraday.use Vhx::Middleware::ErrorResponse
|
29
|
+
faraday.response :json
|
30
|
+
end
|
31
|
+
@connection
|
32
|
+
end
|
33
|
+
|
34
|
+
def configured_headers
|
35
|
+
if access_token
|
36
|
+
@headers[:Authorization] = "Bearer #{access_token}"
|
37
|
+
elsif api_key
|
38
|
+
@headers[:Authorization] = Faraday::Request::BasicAuthentication.header(api_key, '')
|
39
|
+
end
|
40
|
+
|
41
|
+
@headers
|
42
|
+
end
|
43
|
+
|
44
|
+
def access_token
|
45
|
+
unless oauth_token
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
|
49
|
+
oauth_token.access_token
|
50
|
+
end
|
51
|
+
|
52
|
+
def expired?
|
53
|
+
unless oauth_token
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
oauth_token.expires && oauth_token.expires_at < Time.now.to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
def credentials
|
61
|
+
unless oauth_token
|
62
|
+
return nil
|
63
|
+
end
|
64
|
+
|
65
|
+
oauth_token.to_h
|
66
|
+
end
|
67
|
+
|
68
|
+
def refresh_access_token!
|
69
|
+
conn = @connection.dup
|
70
|
+
conn.headers.delete(:Authorization)
|
71
|
+
response = conn.post do |req|
|
72
|
+
req.url '/oauth/token'
|
73
|
+
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
74
|
+
req.body = {
|
75
|
+
grant_type: 'refresh_token',
|
76
|
+
refresh_token: oauth_token.refresh_token,
|
77
|
+
client_id: client_id,
|
78
|
+
client_secret: client_secret
|
79
|
+
}
|
80
|
+
end
|
81
|
+
@oauth_token = OAuthToken.new(response.body, refreshed = true)
|
82
|
+
|
83
|
+
configure_connection
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/vhx/error.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Vhx
|
2
|
+
class VhxError < StandardError
|
3
|
+
attr_reader :response_body, :response_status, :url, :message
|
4
|
+
|
5
|
+
def initialize(response_body, response_status, url)
|
6
|
+
@response_body = response_body
|
7
|
+
@response_status = response_status
|
8
|
+
@url = url
|
9
|
+
@message = response_body.is_a?(Hash) ? response_body['message'] : response_body.to_s
|
10
|
+
|
11
|
+
super(@message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BadRequestError < VhxError; end
|
16
|
+
class UnauthorizedError < VhxError; end
|
17
|
+
class InvalidTokenError < VhxError; end
|
18
|
+
class PaymentRequiredError < VhxError; end
|
19
|
+
class NotFoundError < VhxError; end
|
20
|
+
class NotAcceptableError < VhxError; end
|
21
|
+
class ServerError < VhxError; end
|
22
|
+
|
23
|
+
class InvalidResourceError < StandardError; end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Vhx
|
2
|
+
module Middleware
|
3
|
+
class ErrorResponse < Faraday::Response::Middleware
|
4
|
+
def on_complete(env)
|
5
|
+
error_class = case env[:status]
|
6
|
+
when 200, 201, 204
|
7
|
+
when 304
|
8
|
+
when 400
|
9
|
+
BadRequestError
|
10
|
+
when 401
|
11
|
+
if env[:body].fetch('message', '').match(/token/)
|
12
|
+
InvalidTokenError
|
13
|
+
else
|
14
|
+
UnauthorizedError
|
15
|
+
end
|
16
|
+
when 402
|
17
|
+
PaymentRequiredError
|
18
|
+
when 404
|
19
|
+
NotFoundError
|
20
|
+
when 406
|
21
|
+
NotAcceptableError
|
22
|
+
else
|
23
|
+
ServerError
|
24
|
+
end
|
25
|
+
|
26
|
+
if error_class
|
27
|
+
raise error_class.new(env[:body], env[:status], env[:url])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Vhx
|
2
|
+
module Middleware
|
3
|
+
class OAuth2 < Faraday::Middleware
|
4
|
+
def call(env)
|
5
|
+
orig_env = env.dup
|
6
|
+
|
7
|
+
begin
|
8
|
+
@app.call(env)
|
9
|
+
rescue InvalidTokenError
|
10
|
+
@vhx_client.refresh_access_token!
|
11
|
+
orig_env[:request_headers].merge!(@vhx_client.configured_headers)
|
12
|
+
@app.call(orig_env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(app, options={})
|
17
|
+
super(app)
|
18
|
+
@vhx_client = options[:vhx_client]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class OAuthToken < Struct.new(:access_token, :refresh_token, :expires_at, :expires_in, :expires, :refreshed)
|
2
|
+
def initialize(params = {}, refreshed = false)
|
3
|
+
params = Hash[params.map{ |k, v| [k.to_sym, v] }]
|
4
|
+
self.access_token = params[:access_token]
|
5
|
+
self.refresh_token = params[:refresh_token]
|
6
|
+
self.expires_at = params[:expires_at] || Time.now.to_i + params[:expires_in].to_i
|
7
|
+
self.expires_in = params[:expires_in]
|
8
|
+
self.expires = (params[:expires_at] || params[:expires_in]) ? true : false
|
9
|
+
self.refreshed = refreshed
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Vhx
|
2
|
+
module ApiOperations
|
3
|
+
module Create
|
4
|
+
module ClassMethods
|
5
|
+
def create(payload)
|
6
|
+
klass = get_klass
|
7
|
+
response = Vhx.connection.post do |req|
|
8
|
+
req.url('/' + klass.downcase + 's') #This url is based purely on VHX's API convention.
|
9
|
+
req.body = payload
|
10
|
+
end
|
11
|
+
|
12
|
+
self.new(response.body)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(klass)
|
17
|
+
klass.extend(Vhx::HelperMethods)
|
18
|
+
klass.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Vhx
|
2
|
+
module ApiOperations
|
3
|
+
module Delete
|
4
|
+
module ClassMethods
|
5
|
+
def delete(identifier, payload = {})
|
6
|
+
Vhx.connection.delete(get_hypermedia(identifier), payload)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(klass)
|
11
|
+
klass.extend(Vhx::HelperMethods)
|
12
|
+
klass.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|