nimbu-api 0.0.1

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