nimbu-api 0.0.1

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.
Files changed (66) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +1 -0
  6. data/lib/nimbu-api.rb +43 -0
  7. data/lib/nimbu-api/authentication.rb +76 -0
  8. data/lib/nimbu-api/builder.rb +31 -0
  9. data/lib/nimbu-api/client.rb +26 -0
  10. data/lib/nimbu-api/configuration.rb +109 -0
  11. data/lib/nimbu-api/connection.rb +88 -0
  12. data/lib/nimbu-api/endpoint.rb +199 -0
  13. data/lib/nimbu-api/endpoints/authorizations.rb +113 -0
  14. data/lib/nimbu-api/endpoints/channels.rb +31 -0
  15. data/lib/nimbu-api/endpoints/channels/entries.rb +50 -0
  16. data/lib/nimbu-api/endpoints/sites.rb +34 -0
  17. data/lib/nimbu-api/endpoints/videos.rb +26 -0
  18. data/lib/nimbu-api/errors.rb +31 -0
  19. data/lib/nimbu-api/errors/bad_request.rb +14 -0
  20. data/lib/nimbu-api/errors/client_error.rb +20 -0
  21. data/lib/nimbu-api/errors/forbidden.rb +14 -0
  22. data/lib/nimbu-api/errors/internal_server_error.rb +15 -0
  23. data/lib/nimbu-api/errors/invalid_options.rb +18 -0
  24. data/lib/nimbu-api/errors/not_acceptable.rb +15 -0
  25. data/lib/nimbu-api/errors/not_found.rb +14 -0
  26. data/lib/nimbu-api/errors/required_params.rb +18 -0
  27. data/lib/nimbu-api/errors/service_error.rb +65 -0
  28. data/lib/nimbu-api/errors/service_unavailable.rb +15 -0
  29. data/lib/nimbu-api/errors/unauthorized.rb +15 -0
  30. data/lib/nimbu-api/errors/unknown_value.rb +18 -0
  31. data/lib/nimbu-api/errors/unprocessable_entity.rb +14 -0
  32. data/lib/nimbu-api/errors/validations.rb +18 -0
  33. data/lib/nimbu-api/pagination.rb +106 -0
  34. data/lib/nimbu-api/pagination/page_iterator.rb +157 -0
  35. data/lib/nimbu-api/pagination/page_links.rb +48 -0
  36. data/lib/nimbu-api/pagination/paged_request.rb +41 -0
  37. data/lib/nimbu-api/pagination/pagination.rb +102 -0
  38. data/lib/nimbu-api/request.rb +81 -0
  39. data/lib/nimbu-api/request/arguments.rb +171 -0
  40. data/lib/nimbu-api/request/basic_auth.rb +31 -0
  41. data/lib/nimbu-api/request/json.rb +46 -0
  42. data/lib/nimbu-api/request/normalizer.rb +29 -0
  43. data/lib/nimbu-api/request/oauth2.rb +42 -0
  44. data/lib/nimbu-api/request/parameter_filter.rb +34 -0
  45. data/lib/nimbu-api/request/validations.rb +25 -0
  46. data/lib/nimbu-api/request/validations/format.rb +26 -0
  47. data/lib/nimbu-api/request/validations/presence.rb +32 -0
  48. data/lib/nimbu-api/request/validations/required.rb +26 -0
  49. data/lib/nimbu-api/request/validations/token.rb +35 -0
  50. data/lib/nimbu-api/response.rb +34 -0
  51. data/lib/nimbu-api/response/header.rb +76 -0
  52. data/lib/nimbu-api/response/json.rb +29 -0
  53. data/lib/nimbu-api/response/mashify.rb +24 -0
  54. data/lib/nimbu-api/response/raise_error.rb +18 -0
  55. data/lib/nimbu-api/response/wrapper.rb +149 -0
  56. data/lib/nimbu-api/response/xmlize.rb +26 -0
  57. data/lib/nimbu-api/utils/all.rb +6 -0
  58. data/lib/nimbu-api/utils/constants.rb +37 -0
  59. data/lib/nimbu-api/utils/descendants.rb +11 -0
  60. data/lib/nimbu-api/utils/extend_array.rb +17 -0
  61. data/lib/nimbu-api/utils/extend_hash.rb +73 -0
  62. data/lib/nimbu-api/utils/json.rb +19 -0
  63. data/lib/nimbu-api/utils/url.rb +56 -0
  64. data/lib/nimbu-api/version.rb +3 -0
  65. data/nimbu-api.gemspec +31 -0
  66. metadata +294 -0
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu
4
+ module Error
5
+ class NimbuError < StandardError
6
+ extend ::Nimbu::Utils::Descendants
7
+
8
+ attr_reader :response_message, :response_headers
9
+
10
+ # Initialize a new Nimbu error object.
11
+ #
12
+ def initialize(message=$!)
13
+ if message.respond_to?(:backtrace)
14
+ super(message.message)
15
+ @response_message = message
16
+ else
17
+ super(message.to_s)
18
+ end
19
+ end
20
+
21
+ def backtrace
22
+ @response_message ? @response_message.backtrace : super
23
+ end
24
+
25
+ end # NimbuError
26
+ end # Error
27
+ end # Nimbu
28
+
29
+ %w( service_error bad_request unauthorized forbidden not_found not_acceptable unprocessable_entity internal_server_error service_unavailable client_error invalid_options required_params unknown_value validations ).each do |error|
30
+ require "nimbu-api/errors/#{error}"
31
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu
4
+ module Error
5
+ # Raised when Nimbu returns the HTTP status code 400
6
+ class BadRequest < ServiceError
7
+ http_status_code 400
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+ end
13
+ end
14
+ end # Nimbu
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 404
5
+ module Error
6
+ class ClientError < NimbuError
7
+ attr_reader :problem, :summary, :resolution
8
+
9
+ def initialize(message)
10
+ super(message)
11
+ end
12
+
13
+ def generate_message(attributes)
14
+ "\nProblem:\n #{attributes[:problem]}"+
15
+ "\nSummary:\n #{attributes[:summary]}"+
16
+ "\nResolution:\n #{attributes[:resolution]}"
17
+ end
18
+ end
19
+ end # Error
20
+ end # Nimbu
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 403
5
+ module Error
6
+ class Forbidden < ServiceError
7
+ http_status_code 403
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+ end
13
+ end # Error
14
+ end # Nimbu
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 500
5
+ module Error
6
+ class InternalServerError < ServiceError
7
+ http_status_code 500
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+
13
+ end # InternalServerError
14
+ end # Error
15
+ end # Nimbu
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class InvalidOptions < ClientError
7
+ def initialize(invalid, valid)
8
+ super(
9
+ generate_message(
10
+ :problem => "Invalid option #{invalid.keys.join(', ')} provided for this request.",
11
+ :summary => "Nimbu gem checks the request parameters passed to ensure that Nimbu api is not hit unnecessairly and to fail fast.",
12
+ :resolution => "Valid options are: #{valid.join(', ')}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # Nimbu
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 406
5
+ module Error
6
+ class NotAcceptable < ServiceError
7
+ http_status_code 406
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+
13
+ end # NotAcceptable
14
+ end # Error
15
+ end # Nimbu
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 404
5
+ module Error
6
+ class NotFound < ServiceError
7
+ http_status_code 404
8
+
9
+ def initialize(env)
10
+ super(env)
11
+ end
12
+ end
13
+ end # Error
14
+ end # Nimbu
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class RequiredParams < ClientError
7
+ def initialize(provided, required)
8
+ super(
9
+ generate_message(
10
+ :problem => "Missing required parameters: #{provided.keys.join(', ')} provided for this request.",
11
+ :summary => "Nimbu gem checks the request parameters passed to ensure that Nimbu api is not hit unnecessairly and to fail fast.",
12
+ :resolution => "Required parameters are: #{required.join(', ')}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # Nimbu
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ # require 'multi_json'
3
+ require 'nimbu-api/utils/json'
4
+
5
+ module Nimbu
6
+ # Raised when Nimbu returns any of the HTTP status codes
7
+ module Error
8
+ class ServiceError < NimbuError
9
+ include ::Nimbu::Utils::Json
10
+
11
+ attr_reader :http_headers
12
+
13
+ def initialize(response)
14
+ @http_headers = response[:response_headers]
15
+ message = parse_response(response)
16
+ super(message)
17
+ end
18
+
19
+ def parse_response(response)
20
+ body = parse_body(response[:body])
21
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{response[:status]} #{body}"
22
+ end
23
+
24
+ def decode_body(body)
25
+ if body.respond_to?(:to_str) && body.length >= 2
26
+ decode body, :symbolize_keys => true
27
+ else
28
+ body
29
+ end
30
+ end
31
+
32
+ def parse_body(body)
33
+ body = decode_body(body)
34
+
35
+ return '' if body.nil? || body.empty?
36
+
37
+ if body[:error]
38
+ body[:error]
39
+ elsif body[:errors]
40
+ error = Array(body[:errors]).first
41
+ if error.kind_of?(Hash)
42
+ error[:message]
43
+ else
44
+ error
45
+ end
46
+ elsif body[:message]
47
+ body[:message]
48
+ else
49
+ ''
50
+ end
51
+ end
52
+
53
+ def self.http_status_code(code)
54
+ define_method(:http_status_code) { code }
55
+ end
56
+
57
+ def self.errors
58
+ @errors ||= Hash[
59
+ descendants.map { |klass| [klass.new({}).http_status_code, klass] }
60
+ ]
61
+ end
62
+
63
+ end
64
+ end # Error
65
+ end # Nimbu
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 503
5
+ module Error
6
+ class ServiceUnavailable < ServiceError
7
+ http_status_code 503
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+
13
+ end # ServiceUnavailable
14
+ end # Error
15
+ end # Nimbu
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 401
5
+ module Error
6
+ class Unauthorized < ServiceError
7
+ http_status_code 401
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+
13
+ end # Unauthorized
14
+ end # Error
15
+ end # Nimbu
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class UnknownValue < ClientError
7
+ def initialize(key, value, permitted)
8
+ super(
9
+ generate_message(
10
+ :problem => "Wrong value of '#{value}' for the parameter: #{key} provided for this request.",
11
+ :summary => "Nimbu gem checks the request parameters passed to ensure that Nimbu api is not hit unnecessairly and fails fast.",
12
+ :resolution => "Permitted values are: #{permitted}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # Nimbu
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when Nimbu returns the HTTP status code 422
5
+ module Error
6
+ class UnprocessableEntity < ServiceError
7
+ http_status_code 422
8
+
9
+ def initialize(response)
10
+ super(response)
11
+ end
12
+ end
13
+ end # Error
14
+ end # Nimbu
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Nimbu #:nodoc
4
+ # Raised when passed parameters are missing or contain wrong values.
5
+ module Error
6
+ class Validations < ClientError
7
+ def initialize(errors)
8
+ super(
9
+ generate_message(
10
+ :problem => "Attempted to send request with nil arguments for #{errors.keys.join(', ')}.",
11
+ :summary => 'Each request expects certain number of required arguments.',
12
+ :resolution => 'Double check that the provided arguments are set to some value that is neither nil nor empty string.'
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # Nimbu
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+
3
+ require 'nimbu-api/pagination/paged_request'
4
+ require 'nimbu-api/pagination/page_iterator'
5
+ require 'nimbu-api/pagination/page_links'
6
+
7
+ module Nimbu
8
+
9
+ # A module that decorates response with pagination helpers
10
+ module Pagination
11
+ include Nimbu::Utils::Constants
12
+
13
+ # Return page links
14
+ def links
15
+ @links = Nimbu::Pagination::PageLinks.new(env[:response_headers])
16
+ end
17
+
18
+ # Retrive number of total pages base on current :per_page parameter
19
+ def count_pages
20
+ page_iterator.count.to_i
21
+ end
22
+
23
+ # Iterate over results set pages by automatically calling `next_page`
24
+ # until all pages are exhausted. Caution needs to be exercised when
25
+ # using this feature - 100 pages iteration will perform 100 API calls.
26
+ # By default this is off. You can set it on the client, individual API
27
+ # instances or just per given request.
28
+ #
29
+ def auto_paginate(auto=false)
30
+ if links.any? && (current_api.auto_pagination? || auto)
31
+ resources_bodies = []
32
+ each_page { |resource| resources_bodies += resource.body }
33
+ self.body = resources_bodies
34
+ end
35
+ self
36
+ end
37
+
38
+ # Iterator like each for response pages. If there are no pages to
39
+ # iterate over this method will return current page.
40
+ def each_page
41
+ yield self
42
+ while page_iterator.has_next?
43
+ yield next_page
44
+ end
45
+ end
46
+
47
+ # Retrives the result of the first page. Returns <tt>nil</tt> if there is
48
+ # no first page - either because you are already on the first page
49
+ # or there are no pages at all in the result.
50
+ def first_page
51
+ first_request = page_iterator.first
52
+ self.instance_eval { @env = first_request.env } if first_request
53
+ first_request
54
+ end
55
+
56
+ # Retrives the result of the next page. Returns <tt>nil</tt> if there is
57
+ # no next page or no pages at all.
58
+ def next_page
59
+ next_request = page_iterator.next
60
+ self.instance_eval { @env = next_request.env } if next_request
61
+ next_request
62
+ end
63
+
64
+ # Retrives the result of the previous page. Returns <tt>nil</tt> if there is
65
+ # no previous page or no pages at all.
66
+ def prev_page
67
+ prev_request = page_iterator.prev
68
+ self.instance_eval { @env = prev_request.env } if prev_request
69
+ prev_request
70
+ end
71
+ alias :previous_page :prev_page
72
+
73
+ # Retrives the result of the last page. Returns <tt>nil</tt> if there is
74
+ # no last page - either because you are already on the last page,
75
+ # there is only one page or there are no pages at all in the result.
76
+ def last_page
77
+ last_request = page_iterator.last
78
+ self.instance_eval { @env = last_request.env } if last_request
79
+ last_request
80
+ end
81
+
82
+ # Retrives a specific result for a page given page number.
83
+ # The <tt>page_number</tt> parameter is not validate, hitting a page
84
+ # that does not exist will return Nimbu API error. Consequently, if
85
+ # there is only one page, this method returns nil
86
+ def page(page_number)
87
+ request = page_iterator.get_page(page_number)
88
+ self.instance_eval { @env = request.env } if request
89
+ request
90
+ end
91
+
92
+ # Returns <tt>true</tt> if there is another page in the result set,
93
+ # otherwise <tt>false</tt>
94
+ def has_next_page?
95
+ page_iterator.has_next?
96
+ end
97
+
98
+ private
99
+
100
+ # Internally used page iterator
101
+ def page_iterator # :nodoc:
102
+ @page_iterator = Nimbu::Pagination::PageIterator.new(links, current_api)
103
+ end
104
+
105
+ end # Pagination
106
+ end # Nimbu
@@ -0,0 +1,157 @@
1
+ # encoding: utf-8
2
+
3
+ require 'nimbu-api/utils/url'
4
+ require 'uri'
5
+
6
+ module Nimbu
7
+ module Pagination
8
+ class PageIterator
9
+ include Nimbu::Utils::Constants
10
+ include Nimbu::Utils::Url
11
+ include PagedRequest
12
+
13
+ # Setup attribute accesor for all the link types
14
+ ATTRIBUTES = [ META_FIRST, META_NEXT, META_PREV, META_LAST ]
15
+
16
+ ATTRIBUTES.each do |attr|
17
+ attr_accessor :"#{attr}_page_uri", :"#{attr}_page"
18
+ end
19
+
20
+ attr_reader :current_api
21
+
22
+ def initialize(links, current_api)
23
+ @links = links
24
+ @current_api = current_api
25
+ update_page_links @links
26
+ end
27
+
28
+ def has_next?
29
+ next_page == 0 || !next_page_uri.nil?
30
+ end
31
+
32
+ def count
33
+ return nil unless last_page_uri
34
+ parse_query(URI(last_page_uri).query)['page']
35
+ end
36
+
37
+ # Perform http get request for the first resource
38
+ #
39
+ def first
40
+ return nil unless first_page_uri
41
+ page_uri = URI(first_page_uri)
42
+ params = parse_query(page_uri.query)
43
+ if next_page < 1
44
+ params['sha'] = 'master' if params.keys.include?('sha')
45
+ params['per_page'] = parse_per_page_number(first_page_uri)
46
+ else
47
+ params['page'] = parse_page_number(first_page_uri)
48
+ params['per_page'] = parse_per_page_number(first_page_uri)
49
+ end
50
+
51
+ response = page_request(page_uri.path, params)
52
+ update_page_links response.links
53
+ response
54
+ end
55
+
56
+ # Perform http get request for the next resource
57
+ #
58
+ def next
59
+ return nil unless has_next?
60
+ page_uri = URI(next_page_uri)
61
+ params = parse_query(page_uri.query)
62
+ if next_page < 1
63
+ params['sha'] = params['last_sha'] if params.keys.include?('last_sha')
64
+ params['per_page'] = parse_per_page_number(next_page_uri)
65
+ else
66
+ params['page'] = parse_page_number(next_page_uri)
67
+ params['per_page'] = parse_per_page_number(next_page_uri)
68
+ end
69
+
70
+ response = page_request(page_uri.path, params)
71
+ update_page_links response.links
72
+ response
73
+ end
74
+
75
+ # Perform http get request for the previous resource
76
+ #
77
+ def prev
78
+ return nil unless prev_page_uri
79
+ page_uri = URI(prev_page_uri)
80
+ params = parse_query(page_uri.query)
81
+ params['page'] = parse_page_number(prev_page_uri)
82
+ params['per_page'] = parse_per_page_number(prev_page_uri)
83
+
84
+ response = page_request(page_uri.path, params)
85
+ update_page_links response.links
86
+ response
87
+ end
88
+
89
+ # Perform http get request for the last resource
90
+ #
91
+ def last
92
+ return nil unless last_page_uri
93
+ page_uri = URI(last_page_uri)
94
+ params = parse_query(page_uri.query)
95
+ params['page'] = parse_page_number(last_page_uri)
96
+ params['per_page'] = parse_per_page_number(last_page_uri)
97
+
98
+ response = page_request(page_uri.path, params)
99
+ update_page_links response.links
100
+ response
101
+ end
102
+
103
+ # Returns the result for a specific page.
104
+ #
105
+ def get_page(page_number)
106
+ # Find URI that we can work with, if we cannot get the first or the
107
+ # last page URI then there is only one page.
108
+ page_uri = first_page_uri || last_page_uri
109
+ return nil unless page_uri
110
+ params = parse_query URI(page_uri).query
111
+ params['page'] = page_number
112
+ params['per_page'] = parse_per_page_number(page_uri)
113
+
114
+ response = page_request URI(page_uri).path, params
115
+ update_page_links response.links
116
+ response
117
+ end
118
+
119
+ private
120
+
121
+ def parse_per_page_number(uri) # :nodoc:
122
+ parse_page_params(uri, PARAM_PER_PAGE)
123
+ end
124
+
125
+ def parse_page_number(uri) # :nodoc:
126
+ parse_page_params(uri, PARAM_PAGE)
127
+ end
128
+
129
+ # Extracts query string parameter for given name
130
+ def parse_page_params(uri, attr) # :nodoc:
131
+ return -1 if uri.nil? || uri.empty?
132
+ parsed = nil
133
+ begin
134
+ parsed = URI.parse(uri)
135
+ rescue URI::Error => e
136
+ return -1
137
+ end
138
+ param = parse_query_for_param(parsed.query, attr)
139
+ return -1 if param.nil? || param.empty?
140
+ begin
141
+ return param.to_i
142
+ rescue ArgumentError => err
143
+ return -1
144
+ end
145
+ end
146
+
147
+ # Wholesale update of all link attributes
148
+ def update_page_links(links) # :nodoc:
149
+ ATTRIBUTES.each do |attr|
150
+ self.send(:"#{attr}_page_uri=", links.send(:"#{attr}"))
151
+ self.send(:"#{attr}_page=", parse_page_number(links.send(:"#{attr}")))
152
+ end
153
+ end
154
+
155
+ end # PageIterator
156
+ end # Pagination
157
+ end # Nimbu