hoodoo 1.0.2

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 (216) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hoodoo +5 -0
  3. data/lib/hoodoo.rb +27 -0
  4. data/lib/hoodoo/active.rb +32 -0
  5. data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
  6. data/lib/hoodoo/active/active_record/base.rb +81 -0
  7. data/lib/hoodoo/active/active_record/creator.rb +134 -0
  8. data/lib/hoodoo/active/active_record/dated.rb +343 -0
  9. data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
  10. data/lib/hoodoo/active/active_record/finder.rb +606 -0
  11. data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
  12. data/lib/hoodoo/active/active_record/secure.rb +431 -0
  13. data/lib/hoodoo/active/active_record/support.rb +106 -0
  14. data/lib/hoodoo/active/active_record/translated.rb +87 -0
  15. data/lib/hoodoo/active/active_record/uuid.rb +80 -0
  16. data/lib/hoodoo/active/active_record/writer.rb +321 -0
  17. data/lib/hoodoo/client.rb +23 -0
  18. data/lib/hoodoo/client/augmented_array.rb +29 -0
  19. data/lib/hoodoo/client/augmented_base.rb +168 -0
  20. data/lib/hoodoo/client/augmented_hash.rb +23 -0
  21. data/lib/hoodoo/client/client.rb +354 -0
  22. data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
  23. data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
  24. data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
  25. data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
  26. data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
  27. data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
  28. data/lib/hoodoo/client/headers.rb +269 -0
  29. data/lib/hoodoo/communicators.rb +23 -0
  30. data/lib/hoodoo/communicators/fast.rb +44 -0
  31. data/lib/hoodoo/communicators/pool.rb +601 -0
  32. data/lib/hoodoo/communicators/slow.rb +84 -0
  33. data/lib/hoodoo/data.rb +51 -0
  34. data/lib/hoodoo/data/resources/caller.rb +39 -0
  35. data/lib/hoodoo/data/resources/errors.rb +28 -0
  36. data/lib/hoodoo/data/resources/log.rb +31 -0
  37. data/lib/hoodoo/data/resources/session.rb +26 -0
  38. data/lib/hoodoo/data/types/error_primitive.rb +27 -0
  39. data/lib/hoodoo/data/types/permissions.rb +40 -0
  40. data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
  41. data/lib/hoodoo/data/types/permissions_full.rb +28 -0
  42. data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
  43. data/lib/hoodoo/discovery.rb +20 -0
  44. data/lib/hoodoo/errors.rb +19 -0
  45. data/lib/hoodoo/errors/error_descriptions.rb +229 -0
  46. data/lib/hoodoo/errors/errors.rb +322 -0
  47. data/lib/hoodoo/generator.rb +139 -0
  48. data/lib/hoodoo/logger.rb +23 -0
  49. data/lib/hoodoo/logger/fast_writer.rb +27 -0
  50. data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
  51. data/lib/hoodoo/logger/logger.rb +387 -0
  52. data/lib/hoodoo/logger/slow_writer.rb +49 -0
  53. data/lib/hoodoo/logger/writer_mixin.rb +52 -0
  54. data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
  55. data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
  56. data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
  57. data/lib/hoodoo/middleware.rb +33 -0
  58. data/lib/hoodoo/presenters.rb +45 -0
  59. data/lib/hoodoo/presenters/base.rb +281 -0
  60. data/lib/hoodoo/presenters/base_dsl.rb +519 -0
  61. data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
  62. data/lib/hoodoo/presenters/embedding.rb +232 -0
  63. data/lib/hoodoo/presenters/types/array.rb +118 -0
  64. data/lib/hoodoo/presenters/types/boolean.rb +26 -0
  65. data/lib/hoodoo/presenters/types/date.rb +26 -0
  66. data/lib/hoodoo/presenters/types/date_time.rb +26 -0
  67. data/lib/hoodoo/presenters/types/decimal.rb +47 -0
  68. data/lib/hoodoo/presenters/types/enum.rb +55 -0
  69. data/lib/hoodoo/presenters/types/field.rb +158 -0
  70. data/lib/hoodoo/presenters/types/float.rb +26 -0
  71. data/lib/hoodoo/presenters/types/hash.rb +361 -0
  72. data/lib/hoodoo/presenters/types/integer.rb +26 -0
  73. data/lib/hoodoo/presenters/types/object.rb +117 -0
  74. data/lib/hoodoo/presenters/types/string.rb +53 -0
  75. data/lib/hoodoo/presenters/types/tags.rb +24 -0
  76. data/lib/hoodoo/presenters/types/text.rb +26 -0
  77. data/lib/hoodoo/presenters/types/uuid.rb +54 -0
  78. data/lib/hoodoo/services.rb +34 -0
  79. data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
  80. data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
  81. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
  82. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
  83. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
  84. data/lib/hoodoo/services/discovery/discovery.rb +186 -0
  85. data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
  86. data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
  87. data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
  88. data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
  89. data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
  90. data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
  91. data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
  92. data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
  93. data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
  94. data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
  95. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
  96. data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
  97. data/lib/hoodoo/services/middleware/interaction.rb +127 -0
  98. data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
  99. data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
  100. data/lib/hoodoo/services/services/context.rb +153 -0
  101. data/lib/hoodoo/services/services/implementation.rb +132 -0
  102. data/lib/hoodoo/services/services/interface.rb +934 -0
  103. data/lib/hoodoo/services/services/permissions.rb +250 -0
  104. data/lib/hoodoo/services/services/request.rb +189 -0
  105. data/lib/hoodoo/services/services/response.rb +316 -0
  106. data/lib/hoodoo/services/services/service.rb +141 -0
  107. data/lib/hoodoo/services/services/session.rb +729 -0
  108. data/lib/hoodoo/utilities.rb +12 -0
  109. data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
  110. data/lib/hoodoo/utilities/utilities.rb +380 -0
  111. data/lib/hoodoo/utilities/uuid.rb +44 -0
  112. data/lib/hoodoo/version.rb +17 -0
  113. data/spec/active/active_record/base_spec.rb +57 -0
  114. data/spec/active/active_record/creator_spec.rb +88 -0
  115. data/spec/active/active_record/dated_spec.rb +248 -0
  116. data/spec/active/active_record/error_mapping_spec.rb +360 -0
  117. data/spec/active/active_record/finder_spec.rb +744 -0
  118. data/spec/active/active_record/search_helper_spec.rb +384 -0
  119. data/spec/active/active_record/secure_spec.rb +435 -0
  120. data/spec/active/active_record/support_spec.rb +225 -0
  121. data/spec/active/active_record/translated_spec.rb +19 -0
  122. data/spec/active/active_record/uuid_spec.rb +72 -0
  123. data/spec/active/active_record/writer_spec.rb +272 -0
  124. data/spec/alchemy/alchemy-amq.rb +33 -0
  125. data/spec/client/augmented_array_spec.rb +15 -0
  126. data/spec/client/augmented_base_spec.rb +50 -0
  127. data/spec/client/augmented_hash_spec.rb +15 -0
  128. data/spec/client/client_spec.rb +955 -0
  129. data/spec/client/endpoint/endpoint_spec.rb +70 -0
  130. data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
  131. data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
  132. data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
  133. data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
  134. data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
  135. data/spec/client/headers_spec.rb +172 -0
  136. data/spec/communicators/fast_spec.rb +9 -0
  137. data/spec/communicators/pool_spec.rb +339 -0
  138. data/spec/communicators/slow_spec.rb +15 -0
  139. data/spec/data/resources/caller_spec.rb +156 -0
  140. data/spec/data/resources/errors_spec.rb +22 -0
  141. data/spec/data/resources/log_spec.rb +20 -0
  142. data/spec/data/resources/session_spec.rb +15 -0
  143. data/spec/data/types/error_primitive_spec.rb +15 -0
  144. data/spec/data/types/permissions_defaults_spec.rb +25 -0
  145. data/spec/data/types/permissions_full_spec.rb +44 -0
  146. data/spec/data/types/permissions_resources_spec.rb +34 -0
  147. data/spec/data/types/permissions_spec.rb +37 -0
  148. data/spec/errors/error_descriptions_spec.rb +98 -0
  149. data/spec/errors/errors_spec.rb +346 -0
  150. data/spec/integration/service_actions_spec.rb +112 -0
  151. data/spec/logger/fast_writer_spec.rb +18 -0
  152. data/spec/logger/logger_spec.rb +259 -0
  153. data/spec/logger/slow_writer_spec.rb +144 -0
  154. data/spec/logger/writers/file_writer_spec.rb +37 -0
  155. data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
  156. data/spec/logger/writers/stream_writer_spec.rb +38 -0
  157. data/spec/presenters/base_dsl_spec.rb +111 -0
  158. data/spec/presenters/base_spec.rb +871 -0
  159. data/spec/presenters/common_resource_fields_spec.rb +30 -0
  160. data/spec/presenters/embedding_spec.rb +87 -0
  161. data/spec/presenters/types/array_spec.rb +249 -0
  162. data/spec/presenters/types/boolean_spec.rb +51 -0
  163. data/spec/presenters/types/date_spec.rb +57 -0
  164. data/spec/presenters/types/date_time_spec.rb +59 -0
  165. data/spec/presenters/types/decimal_spec.rb +58 -0
  166. data/spec/presenters/types/enum_spec.rb +71 -0
  167. data/spec/presenters/types/field_spec.rb +77 -0
  168. data/spec/presenters/types/float_spec.rb +50 -0
  169. data/spec/presenters/types/hash_spec.rb +1069 -0
  170. data/spec/presenters/types/integer_spec.rb +50 -0
  171. data/spec/presenters/types/object_spec.rb +177 -0
  172. data/spec/presenters/types/string_spec.rb +65 -0
  173. data/spec/presenters/types/tags_spec.rb +56 -0
  174. data/spec/presenters/types/text_spec.rb +50 -0
  175. data/spec/presenters/types/uuid_spec.rb +46 -0
  176. data/spec/presenters/walk_spec.rb +198 -0
  177. data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
  178. data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
  179. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
  180. data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
  181. data/spec/services/discovery/discovery_spec.rb +73 -0
  182. data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
  183. data/spec/services/discovery/results/for_http_spec.rb +37 -0
  184. data/spec/services/discovery/results/for_local_spec.rb +21 -0
  185. data/spec/services/discovery/results/for_remote_spec.rb +15 -0
  186. data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
  187. data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
  188. data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
  189. data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
  190. data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
  191. data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
  192. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
  193. data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
  194. data/spec/services/middleware/middleware_cors_spec.rb +93 -0
  195. data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
  196. data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
  197. data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
  198. data/spec/services/middleware/middleware_logging_spec.rb +356 -0
  199. data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
  200. data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
  201. data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
  202. data/spec/services/middleware/middleware_public_spec.rb +238 -0
  203. data/spec/services/middleware/middleware_spec.rb +1569 -0
  204. data/spec/services/middleware/string_inquirer_spec.rb +30 -0
  205. data/spec/services/services/application_spec.rb +74 -0
  206. data/spec/services/services/context_spec.rb +48 -0
  207. data/spec/services/services/implementation_spec.rb +45 -0
  208. data/spec/services/services/interface_spec.rb +262 -0
  209. data/spec/services/services/permissions_spec.rb +249 -0
  210. data/spec/services/services/request_spec.rb +95 -0
  211. data/spec/services/services/response_spec.rb +250 -0
  212. data/spec/services/services/session_spec.rb +432 -0
  213. data/spec/spec_helper.rb +298 -0
  214. data/spec/utilities/utilities_spec.rb +537 -0
  215. data/spec/utilities/uuid_spec.rb +20 -0
  216. metadata +615 -0
@@ -0,0 +1,23 @@
1
+ ########################################################################
2
+ # File:: client.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: Include code that makes it easy to call resource endpoints.
6
+ # ----------------------------------------------------------------------
7
+ # 10-Mar-2015 (ADH): Created
8
+ ########################################################################
9
+
10
+ require 'hoodoo/client/headers'
11
+
12
+ require 'hoodoo/client/augmented_base'
13
+ require 'hoodoo/client/augmented_hash'
14
+ require 'hoodoo/client/augmented_array'
15
+
16
+ require 'hoodoo/client/endpoint/endpoint'
17
+ require 'hoodoo/client/endpoint/endpoints/http_based'
18
+ require 'hoodoo/client/endpoint/endpoints/http'
19
+ require 'hoodoo/client/endpoint/endpoints/amqp'
20
+ require 'hoodoo/client/endpoint/endpoints/not_found'
21
+ require 'hoodoo/client/endpoint/endpoints/auto_session'
22
+
23
+ require 'hoodoo/client/client'
@@ -0,0 +1,29 @@
1
+ ########################################################################
2
+ # File:: augmented_array.rb.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: A subclass of Ruby standard library Array used by the
6
+ # Hoodoo::Client::Endpoint family.
7
+ # ----------------------------------------------------------------------
8
+ # 11-Dec-2014 (ADH): Created.
9
+ # 05-Mar-2015 (ADH): Moved to Hoodoo::Client.
10
+ ########################################################################
11
+
12
+ module Hoodoo
13
+ class Client # Just used as a namespace here
14
+
15
+ # Ruby standard library Array subclass which mixes in
16
+ # Hoodoo::Client::AugmentedBase. See that for details.
17
+ #
18
+ class AugmentedArray < ::Array
19
+ include Hoodoo::Client::AugmentedBase
20
+
21
+ # For lists, the (optional) total size of the data set, of which
22
+ # the contents of this Array will often only represent a single
23
+ # page. If unknown, the value is +nil+.
24
+ #
25
+ attr_accessor :dataset_size
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,168 @@
1
+ ########################################################################
2
+ # File:: augmented_array.rb.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: A subclass of Ruby standard library Array used by the
6
+ # Hoodoo::Client::Endpoint family.
7
+ # ----------------------------------------------------------------------
8
+ # 11-Dec-2014 (ADH): Created.
9
+ # 05-Mar-2015 (ADH): Moved to Hoodoo::Client.
10
+ ########################################################################
11
+
12
+ module Hoodoo
13
+ class Client # Just used as a namespace here
14
+
15
+ # Base mixin for Hoodoo::Client::AugmentedHash and
16
+ # Hoodoo::Client::AugmentedArray, used by the
17
+ # Hoodoo::Client::Endpoint family for return
18
+ # values in its resource calling API - see:
19
+ #
20
+ # * Hoodoo::Client::Endpoint#list
21
+ # * Hoodoo::Client::Endpoint#show
22
+ # * Hoodoo::Client::Endpoint#create
23
+ # * Hoodoo::Client::Endpoint#update
24
+ # * Hoodoo::Client::Endpoint#delete
25
+ #
26
+ # The error handling mechanism this mixin provides is intentionally
27
+ # analogous to that used for mapping ActiveRecord model validation
28
+ # failures to platform errors in Hoodoo::ActiveRecord::ErrorMapping
29
+ # for when resource endpoint implementations are calling other
30
+ # resource endpoint implementations, while also supporting use cases
31
+ # of external callers wanting to communicate with resources from
32
+ # "outside the system".
33
+ #
34
+ module AugmentedBase
35
+
36
+ # This call is typically used by resource endpoint implementations
37
+ # ("service authors") during inter-resource calls, rather than by
38
+ # external entities calling into a system via Hoodoo::Client.
39
+ #
40
+ # Errors set via #set_platform_errors are added to the
41
+ # given Hoodoo::Errors instance. Generally, #set_platform_errors is
42
+ # only called by the Hoodoo::Client under-the-hood implementation
43
+ # code as part of routine error handling.
44
+ #
45
+ # Returns +true+ if any errors were added else +false+ if everything
46
+ # is OK (no platform errors have been noted internally).
47
+ #
48
+ # This makes the idiomatic example for "make inter-resource call,
49
+ # add any errors to my service's response and return on error" very
50
+ # simple, at the expense of modifying the passed-in error collection
51
+ # contents (mutating a parameter is a risky pattern). For an
52
+ # alternative pattern which avoids this, see #platform_errors.
53
+ #
54
+ # Otherwise, a hypothetical resource +Member+ could be listed as
55
+ # follows, as part of a hypothetical +show+ implementation of some
56
+ # other resource:
57
+ #
58
+ # def show( context )
59
+ # list = context.resource( :Member ).list()
60
+ # return if list.adds_errors_to?( context.response.errors )
61
+ # # ...
62
+ # end
63
+ #
64
+ # External callers that have nothing to do with resource endpoint
65
+ # implementations could still construct an errors collection manually
66
+ # and make use of this method, but calling #platform_errors makes a
67
+ # lot more sense for that use case.
68
+ #
69
+ # +collection+:: A Hoodoo::Errors instance, typically obtained
70
+ # from the Hoodoo::Services::Context instance passed to
71
+ # a service implementation in calls like
72
+ # Hoodoo::Services::Implementation#list or
73
+ # Hoodoo::Services::Implementation#show, via
74
+ # +context.response.errors+
75
+ # (i.e. Hoodoo::Services::Context#response /
76
+ # Hoodoo::Services::Response#errors). The collection you
77
+ # pass is updated with any errors noted internally via
78
+ # (usually-middleware-automatically-called) method
79
+ # #set_platform_errors.
80
+ #
81
+ def adds_errors_to?( collection )
82
+ to_add = self.platform_errors()
83
+
84
+ if to_add.has_errors?
85
+ collection.merge!( to_add )
86
+ return true
87
+ else
88
+ return false
89
+ end
90
+ end
91
+
92
+ # This call is typically used by external entities calling into a
93
+ # system via Hoodoo::Client.
94
+ #
95
+ # Returns a Hoodoo::Errors instance that's either been assigned
96
+ # via #set_platform_errors or is an empty, internally assigned
97
+ # collection. This method is very closely related to
98
+ # #adds_errors_to? and, if you have not already done so, you should
99
+ # read that method's documentation before continuing.
100
+ #
101
+ # For external client users, the error handling pattern is:
102
+ #
103
+ # client = Hoodoo::Client.new( ... )
104
+ # endpoint = client.resource( 'Foo' )
105
+ # result = endpoint.show/list/create/update/delete( ... )
106
+ #
107
+ # if result.platform_errors.halt_processing?
108
+ # # Handle result.platform_errors's error data
109
+ # else
110
+ # # Success case
111
+ # end
112
+ #
113
+ # For service authors, the #platform_errors method supports a
114
+ # slightly more verbose form of error handling for inter-resource
115
+ # calls that avoids changing a passed in parameter in the manner
116
+ # of #adds_errors_to?. Compare the idiom shown there:
117
+ #
118
+ # return if list.adds_errors_to?( context.response.errors )
119
+ #
120
+ # ...with the idiomatic use of this method:
121
+ #
122
+ # context.response.add_errors( list.platform_errors )
123
+ # return if context.response.halt_processing?
124
+ #
125
+ # It is a little more verbose and very slightly less efficient as
126
+ # it involves more method calls end to end, but you may prefer the
127
+ # conceptually cleaner approach. You can lean on the return value
128
+ # of #add_errors and end up back at one line of (very slightly less
129
+ # obvious) code, too:
130
+ #
131
+ # return if context.response.add_errors( list.platform_errors )
132
+ #
133
+ def platform_errors
134
+ @nz_co_loyalty_platform_errors ||= Hoodoo::Errors.new
135
+ end
136
+
137
+ # Sets the Hoodoo::Errors instance used by #adds_errors_to? or
138
+ # returned by #platform_errors.
139
+ #
140
+ # It is expected that only Hoodoo::Client-family code will call this
141
+ # method as part of general error handling, though client code may
142
+ # find other uses that are independent of the inter-resource call
143
+ # case wherein the method may be safely invoked.
144
+ #
145
+ def set_platform_errors( errors )
146
+ @nz_co_loyalty_platform_errors = errors
147
+ end
148
+
149
+ # On success, this Hash may be updated with options describing
150
+ # 'out-of-band' information associated with the response, derived from
151
+ # HTTP headers for HTTP-based transports. Non-HTTP transports still
152
+ # carry HTTP-like headers and apply equally here.
153
+ #
154
+ # For more about the mapping from header to option, see class method
155
+ # Hoodoo::Client::Headers.x_header_to_options. Since Hoodoo itself
156
+ # sets up <tt>X-Interaction-ID</tt> and <tt>X-Service-Response-Time</tt>
157
+ # headers in _most_ cases, you can expect to at least find the options
158
+ # +interaction_id+ and +service_response_time+ set for successful calls.
159
+ #
160
+ # Under some circustances, especially for certain error conditions, the
161
+ # value may be +nil+, though Hoodoo endeavours to avoid this and at
162
+ # least fill in +interaction_id+ where possible.
163
+ #
164
+ attr_accessor :response_options
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,23 @@
1
+ ########################################################################
2
+ # File:: augmented_array.rb.rb
3
+ # (C):: Loyalty New Zealand 2014
4
+ #
5
+ # Purpose:: A subclass of Ruby standard library Array used by the
6
+ # Hoodoo::Client::Endpoint family.
7
+ # ----------------------------------------------------------------------
8
+ # 11-Dec-2014 (ADH): Created.
9
+ # 05-Mar-2015 (ADH): Moved to Hoodoo::Client.
10
+ ########################################################################
11
+
12
+ module Hoodoo
13
+ class Client # Just used as a namespace here
14
+
15
+ # Ruby standard library Hash subclass which mixes in
16
+ # Hoodoo::Client::AugmentedBase. See that for details.
17
+ #
18
+ class AugmentedHash < ::Hash
19
+ include Hoodoo::Client::AugmentedBase
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,354 @@
1
+ ########################################################################
2
+ # File:: client.rb
3
+ # (C):: Loyalty New Zealand 2015
4
+ #
5
+ # Purpose:: Easy communication with Resource implementations.
6
+ # ----------------------------------------------------------------------
7
+ # 25-Feb-2015 (ADH): Created.
8
+ ########################################################################
9
+
10
+ require 'hoodoo/client/headers'
11
+
12
+ module Hoodoo
13
+
14
+ # Hoodoo::Client provides a high-level abstracted interface for making
15
+ # calls to Resource implementations. A Client instance is created and used
16
+ # as a factory for objects representing individual Resources. Callers use
17
+ # a consistent, high level interface in these objects to make requests to
18
+ # those Resources and do not usually need to worry about where
19
+ # implementations are, or how they are being contacted.
20
+ #
21
+ # Please see the constructor documentation for full details.
22
+ #
23
+ class Client
24
+
25
+ public
26
+
27
+ # Create a client instance. This is used as a factory for endpoint
28
+ # instances which communicate with Resource implementations.
29
+ #
30
+ # == Overview
31
+ #
32
+ # Suppose you have Resources with only +public_actions+ so that no
33
+ # sessions are needed, with resource implementations running at host
34
+ # "test.com" on paths which follow downcase/pluralisation conventions.
35
+ # In this case, creating a Client instance can be as simple as:
36
+ #
37
+ # client = Hoodoo::Client.new(
38
+ # base_uri: 'http://test.com/',
39
+ # auto_session: false
40
+ # )
41
+ #
42
+ # Ask this client for an endpoint of Resource "Member" implementing
43
+ # version 2 of its interface:
44
+ #
45
+ # members = client.resource( :Member, 2 )
46
+ #
47
+ # Perform operations on the endpoints according to the methods in the
48
+ # base class - see these for details:
49
+ #
50
+ # * Hoodoo::Client::Endpoint#list
51
+ # * Hoodoo::Client::Endpoint#show
52
+ # * Hoodoo::Client::Endpoint#create
53
+ # * Hoodoo::Client::Endpoint#update
54
+ # * Hoodoo::Client::Endpoint#delete
55
+ #
56
+ # The above reference describes the basic approach for each call, with
57
+ # common parameters such as the query hash or body hash data described
58
+ # in the base class constructor, Hoodoo::Client::Endpoint#new.
59
+ #
60
+ # As an example, we could list records 50-79 inclusive of "Member"
61
+ # sorted by +created_at+ ascending, embedding an "account" for each,
62
+ # where field 'surname' matches 'Smith' - assuming there's an
63
+ # implementation of such a Resource interface available! - as follows:
64
+ #
65
+ # results = members.list(
66
+ # :offset => 50,
67
+ # :limit => 25,
68
+ # :sort => :created_at,
69
+ # :direction => :asc,
70
+ # :embeds => 'account',
71
+ # :search => { :surname => 'Smith' }
72
+ # )
73
+ #
74
+ # This will return a Hoodoo::Client::AugmentedArray. This is an Array
75
+ # subclass which will contain the (up to) 25 results from the above
76
+ # call and supports Hoodoo::Client::AugmentedArray#dataset_size which
77
+ # (if the called Resource endpoint implementation provides the
78
+ # information) gives the total size of the data set at the time of
79
+ # calling.
80
+ #
81
+ # The other 4 methods return a Hoodoo::Client::AugmentedHash. This is a
82
+ # Hash subclass. Both the Array and Hash subclasses provide a common
83
+ # standard way to handle errors. See the documentation of these classes
84
+ # for details; in brief, you _must_ _always_ check for errors before
85
+ # examining the Hash or Array data with a pattern such as this:
86
+ #
87
+ # if results.platform_errors.has_errors?
88
+ # # Examine results.platform_errors, which is a
89
+ # # Hoodoo::Errors instance, and deal with the contents.
90
+ # else
91
+ # # Treat 'results' as a Hash containing the Resource
92
+ # # data (String keys) or Array of Hashes of such data.
93
+ # end
94
+ #
95
+ # == Session management
96
+ #
97
+ # By default, the Hoodoo::Client constructor assumes you want automatic
98
+ # session management.
99
+ #
100
+ # If you want to use automatic sessions, a Resource endpoint which
101
+ # implements the Session Resource interface is required. This must
102
+ # accept a POST (+create+) action with a payload of two JSON fields:
103
+ # +caller_id+ and +authentication_secret+. It must return a Resource
104
+ # with an "id" value that contains the session ID to quote in future
105
+ # requests via the X-Session-ID HTTP header; or it should return an
106
+ # error if the Caller ID and/or authentication secret are incorrect.
107
+ #
108
+ # The Resource is assumed to live at the same base URI and/or be
109
+ # discovered by the same mechanism (e.g. by convention) as everything
110
+ # else you'll use the client instance for. For more about discovery
111
+ # related paramters, see later.
112
+ #
113
+ # You will need to provide the +caller_id+ and +authentication_secret+
114
+ # (as named parameter +caller_secret+) to the constructor. If the name
115
+ # of the Resource implementing the Session interface is not 'Session',
116
+ # or not at version 1, then you can also provide alternatives. For
117
+ # example, suppose we want to use automatic session management for
118
+ # Caller ID "0123" and secret "ABCD" via version 2 of "CustomSession":
119
+ #
120
+ # client = Hoodoo::Client.new(
121
+ # base_uri: 'http://test.com/',
122
+ # auto_session_resource: 'CustomSession',
123
+ # auto_session_version: 2,
124
+ # caller_id: '0123',
125
+ # caller_secret: 'ABCD'
126
+ # )
127
+ #
128
+ # Finally, you can manually supply a session ID externally for the
129
+ # X-Session-ID header through the +session_id+ parameter. This may be
130
+ # used in conjunction with auto-session management; in that case, the
131
+ # given session is used until it expires (a "platform.invalid_session"
132
+ # error is encountered), after which a new one will be obtained.
133
+ #
134
+ # == Discovery parameters
135
+ #
136
+ # The Client instance needs to be able to find the place where the
137
+ # requested Resource implementations are located, which it does using
138
+ # the Hoodoo::Services::Discovery framework. You should read the
139
+ # description of this framework to get a feel for how that works first.
140
+ #
141
+ # One of the following *named* parameters must be supplied in order to
142
+ # choose a discovery engine for finding Resource endpoints:
143
+ #
144
+ # +discoverer+:: The Client needs a *Discoverer* to map from resource
145
+ # names and versions to locations on the Internet of the
146
+ # actual resource endpoint implementation. Via the
147
+ # +discoverer+ parameter, you can explicitly pass a
148
+ # Hoodoo::Services::Discovery subclass instance
149
+ # customised to your own requirements. There are also
150
+ # convenience parameters available - see below - that
151
+ # create discoverer instances for you, covering common
152
+ # use cases. If provided, the +discoverer+ parameter
153
+ # takes precedence over any other parameters below.
154
+ #
155
+ # +base_uri+:: When given, Resource discovery is done by
156
+ # Hoodoo::Services::Discovery::ByConvention. The path
157
+ # that the by-convention discoverer creates is appended
158
+ # to the base URI to build the full URI at which a server
159
+ # implementing each requested Resource endpoint must be
160
+ # listening (else a 404 / 'platform.not_found' response
161
+ # arises). Specify as a String. If provided, the
162
+ # +base_uri+ parameter takes precedence over any other
163
+ # parameters below.
164
+ #
165
+ # +drb_uri+:: When given, Resource discovery is done by
166
+ # Hoodoo::Services::Discovery::ByDRb. A DRb service
167
+ # providing discovery data must be running at the given
168
+ # URI. Specify as a String. See
169
+ # Hoodoo::Services::Discovery::ByDRb::DRbServer and file
170
+ # +drb_server_start.rb+ for more.
171
+ #
172
+ # +drb_port+:: Instead of +drb_uri+, you can provide the port number
173
+ # of a DRb server on localhost. See
174
+ # Hoodoo::Services::Discovery::ByDRb for which of
175
+ # +drb_uri+ or +drb_port+ take precedence, if both are
176
+ # provided.
177
+ #
178
+ # As an example of using a custom Discoverer, consider a simple HTTP
179
+ # case with the +base_uri+ parameter. The default "by convention"
180
+ # discoverer pluralises all paths, but let's say you have exceptions
181
+ # for Version and Health singleton resources which you've elected to
182
+ # place on singular, not plural, paths. You will need to construct a
183
+ # custom discoverer with these exceptions. See the documentation for
184
+ # Hoodoo::Services::Discovery::ByConvention to understand the options
185
+ # passed in for the custom routing information.
186
+ #
187
+ # base_uri = 'https://api.test.com/'
188
+ #
189
+ # discoverer = Hoodoo::Services::Discovery::ByConvention.new(
190
+ # :base_uri => base_uri,
191
+ # :routing => {
192
+ # :Version => { 1 => '/v1/version' },
193
+ # :Health => { 1 => '/v1/health' }
194
+ # }
195
+ # )
196
+ #
197
+ # client = Hoodoo::Client.new(
198
+ # :discoverer => discoverer,
199
+ # # ...other options...
200
+ # )
201
+ #
202
+ # == Other parameters
203
+ #
204
+ # The following additional *named* parameters are all optional:
205
+ #
206
+ # +locale+:: The String given in Content-Language _and_
207
+ # Accept-Language HTTP headers for requests;
208
+ # default is "en-nz".
209
+ #
210
+ # +session_id+:: An optional session ID to be used for the
211
+ # initial X-Session-ID request header value.
212
+ #
213
+ # +auto_session+:: If +false+, automatic session management is
214
+ # disabled. Default is +true+.
215
+ #
216
+ # +auto_session_resource+:: Name of the Resource to use for automatic
217
+ # session management as a String or Symbol.
218
+ # Default is +"Session"+.
219
+ #
220
+ # +auto_session_version+:: Version of the Resource to use for
221
+ # automatic session management as an Integer.
222
+ # Default is 1.
223
+ #
224
+ # +caller_id+:: If using automatic session management, a
225
+ # Caller UUID must be provided. It is used
226
+ # as the +caller_id+ field's value in the
227
+ # POST (+create+) call to the session
228
+ # Resource endpoint.
229
+ #
230
+ # +caller_secret+:: If using automatic session management, a
231
+ # Caller authentication secret must be
232
+ # provide. It is used as the
233
+ # +authentication_secret+ field's value in
234
+ # the POST (+create+) call to the session
235
+ # Resource endpoint.
236
+ #
237
+ # If curious about the implementation details of automatic session
238
+ # management, see the Hoodoo::Client::Endpoints::AutoSession class's
239
+ # code.
240
+ #
241
+ def initialize( base_uri: nil,
242
+ drb_uri: nil,
243
+ drb_port: nil,
244
+ discoverer: nil,
245
+
246
+ locale: nil,
247
+
248
+ session_id: nil,
249
+ auto_session: :true,
250
+ auto_session_resource: 'Session',
251
+ auto_session_version: 1,
252
+ caller_id: nil,
253
+ caller_secret: nil )
254
+
255
+ @base_uri = base_uri
256
+ @drb_uri = drb_uri
257
+ @drb_port = drb_port
258
+
259
+ @locale = locale
260
+
261
+ @discoverer = if discoverer != nil
262
+ discoverer
263
+ elsif @base_uri != nil
264
+ Hoodoo::Services::Discovery::ByConvention.new(
265
+ :base_uri => @base_uri
266
+ )
267
+ elsif @drb_uri != nil || @drb_port != nil
268
+ Hoodoo::Services::Discovery::ByDRb.new(
269
+ :drb_uri => @drb_uri,
270
+ :drb_port => @drb_port
271
+ )
272
+ else
273
+ raise 'Hoodoo::Client: Please pass one of the "discoverer", "base_uri", "drb_uri" or "drb_port" parameters.'
274
+ end
275
+
276
+ # If doing automatic sessions, acquire a session creation endpoint
277
+
278
+ @session_id = session_id
279
+ @caller_id = caller_id
280
+ @caller_secret = caller_secret
281
+
282
+ if auto_session
283
+ @auto_session_endpoint = Hoodoo::Client::Endpoint.endpoint_for(
284
+ auto_session_resource,
285
+ auto_session_version,
286
+ { :discoverer => @discoverer }
287
+ )
288
+ end
289
+ end
290
+
291
+ # Get an endpoint instance which you can use for talking to a Resource.
292
+ # See the constructor for full information.
293
+ #
294
+ # You'll always get an endpoint instance back from this call. If an
295
+ # implementation of the given version of the given Resource cannot be
296
+ # contacted, you will only get a 404 ('platform.not_found') or 408
297
+ # ('platform.timeout') response when you try to make a call to it.
298
+ #
299
+ # +resource+:: Resource name as a Symbol or String (e.g. +:Purchase+).
300
+ #
301
+ # +version+:: Endpoint version as an Integer; optional; default is 1.
302
+ #
303
+ # +options+:: Optional options Hash (see below).
304
+ #
305
+ # The options Hash key/values are as follows:
306
+ #
307
+ # +locale+:: Locale string for request/response, e.g. "en-gb". Optional.
308
+ # If omitted, defaults to the locale set in this Client
309
+ # instance's constructor.
310
+ #
311
+ # OTHERS:: See Hoodoo::Client::Headers' +HEADER_TO_PROPERTY+. All
312
+ # such option keys _MUST_ be Symbols.
313
+ #
314
+ def resource( resource, version = 1, options = {} )
315
+
316
+ endpoint_options = {
317
+ :discoverer => @discoverer,
318
+ :session_id => @session_id,
319
+ :locale => options[ :locale ] || @locale
320
+ }
321
+
322
+ Hoodoo::Client::Headers::HEADER_TO_PROPERTY.each do | rack_header, description |
323
+ property = description[ :property ]
324
+ endpoint_options[ property ] = options[ property ] if options.has_key?( property )
325
+ end
326
+
327
+ endpoint = Hoodoo::Client::Endpoint.endpoint_for(
328
+ resource,
329
+ version,
330
+ endpoint_options
331
+ )
332
+
333
+ unless @auto_session_endpoint.nil?
334
+ remote_discovery_result = Hoodoo::Services::Discovery::ForRemote.new(
335
+ :resource => resource,
336
+ :version => version,
337
+ :wrapped_endpoint => endpoint
338
+ )
339
+
340
+ endpoint = Hoodoo::Client::Endpoint::AutoSession.new(
341
+ resource,
342
+ version,
343
+ :caller_id => @caller_id,
344
+ :caller_secret => @caller_secret,
345
+ :session_endpoint => @auto_session_endpoint,
346
+ :discovery_result => remote_discovery_result
347
+ )
348
+ end
349
+
350
+ return endpoint
351
+ end
352
+
353
+ end
354
+ end